-- | This module contains the basic types used by the library and their typeclass instances.
module RichEnv.Types
  ( -- * Types
    RichEnv (..),
    defaultRichEnv,
    Environment,
    Mappings (..),
    Values (..),
    Prefixes (..),

    -- * Environment transformations
    toEnvironment,
    fromEnvironment,
  )
where

import Data.Aeson (FromJSON, ToJSON)
import Data.Bifunctor (bimap)
import Data.Text (Text)
import Data.Text qualified as T
import GHC.Generics (Generic)
import RichEnv.Types.Mappings (Mappings (..))
import RichEnv.Types.Prefixes (Prefixes (..))
import RichEnv.Types.Values (Values (..))

-- | A list of key-value pairs representing environment variables.
type Environment = [(Text, Text)]

-- | Get back a @[(String, String)]@ from an 'Environment'.
fromEnvironment :: Environment -> [(String, String)]
fromEnvironment :: Environment -> [(String, String)]
fromEnvironment = ((Text, Text) -> (String, String))
-> Environment -> [(String, String)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Text -> String)
-> (Text -> String) -> (Text, Text) -> (String, String)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap Text -> String
T.unpack Text -> String
T.unpack)

-- | Transform the type returned from 'System.Environment.getEnvironment' (@[(String, String)]@) to use 'Text' instead.
toEnvironment :: [(String, String)] -> Environment
toEnvironment :: [(String, String)] -> Environment
toEnvironment = ((String, String) -> (Text, Text))
-> [(String, String)] -> Environment
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((String -> Text)
-> (String -> Text) -> (String, String) -> (Text, Text)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap String -> Text
T.pack String -> Text
T.pack)

-- | Type that represents a set of rules that generate environment variables. A value of this type can be retrieved from a configuration file (e.g. YAML) due to its 'FromJSON' instance, or persisted into one with 'ToJSON'.
data RichEnv = RichEnv
  { -- | A list of environment variables to be set with their values.
    RichEnv -> Values
values :: Values,
    -- | Mappings from one existing environment variable name to another.
    RichEnv -> Mappings
mappings :: Mappings,
    -- | Mappings from different prefixes of existing environment variables to new prefixes.
    RichEnv -> Prefixes
prefixes :: Prefixes
  }
  deriving stock (RichEnv -> RichEnv -> Bool
(RichEnv -> RichEnv -> Bool)
-> (RichEnv -> RichEnv -> Bool) -> Eq RichEnv
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RichEnv -> RichEnv -> Bool
== :: RichEnv -> RichEnv -> Bool
$c/= :: RichEnv -> RichEnv -> Bool
/= :: RichEnv -> RichEnv -> Bool
Eq, Int -> RichEnv -> ShowS
[RichEnv] -> ShowS
RichEnv -> String
(Int -> RichEnv -> ShowS)
-> (RichEnv -> String) -> ([RichEnv] -> ShowS) -> Show RichEnv
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RichEnv -> ShowS
showsPrec :: Int -> RichEnv -> ShowS
$cshow :: RichEnv -> String
show :: RichEnv -> String
$cshowList :: [RichEnv] -> ShowS
showList :: [RichEnv] -> ShowS
Show, (forall x. RichEnv -> Rep RichEnv x)
-> (forall x. Rep RichEnv x -> RichEnv) -> Generic RichEnv
forall x. Rep RichEnv x -> RichEnv
forall x. RichEnv -> Rep RichEnv x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. RichEnv -> Rep RichEnv x
from :: forall x. RichEnv -> Rep RichEnv x
$cto :: forall x. Rep RichEnv x -> RichEnv
to :: forall x. Rep RichEnv x -> RichEnv
Generic)
  deriving anyclass (Maybe RichEnv
Value -> Parser [RichEnv]
Value -> Parser RichEnv
(Value -> Parser RichEnv)
-> (Value -> Parser [RichEnv]) -> Maybe RichEnv -> FromJSON RichEnv
forall a.
(Value -> Parser a)
-> (Value -> Parser [a]) -> Maybe a -> FromJSON a
$cparseJSON :: Value -> Parser RichEnv
parseJSON :: Value -> Parser RichEnv
$cparseJSONList :: Value -> Parser [RichEnv]
parseJSONList :: Value -> Parser [RichEnv]
$comittedField :: Maybe RichEnv
omittedField :: Maybe RichEnv
FromJSON, [RichEnv] -> Value
[RichEnv] -> Encoding
RichEnv -> Bool
RichEnv -> Value
RichEnv -> Encoding
(RichEnv -> Value)
-> (RichEnv -> Encoding)
-> ([RichEnv] -> Value)
-> ([RichEnv] -> Encoding)
-> (RichEnv -> Bool)
-> ToJSON RichEnv
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: RichEnv -> Value
toJSON :: RichEnv -> Value
$ctoEncoding :: RichEnv -> Encoding
toEncoding :: RichEnv -> Encoding
$ctoJSONList :: [RichEnv] -> Value
toJSONList :: [RichEnv] -> Value
$ctoEncodingList :: [RichEnv] -> Encoding
toEncodingList :: [RichEnv] -> Encoding
$comitField :: RichEnv -> Bool
omitField :: RichEnv -> Bool
ToJSON)

instance Semigroup RichEnv where
  (<>) :: RichEnv -> RichEnv -> RichEnv
  <> :: RichEnv -> RichEnv -> RichEnv
(<>) (RichEnv Values
a Mappings
b Prefixes
c) (RichEnv Values
d Mappings
e Prefixes
f) = Values -> Mappings -> Prefixes -> RichEnv
RichEnv (Values
a Values -> Values -> Values
forall a. Semigroup a => a -> a -> a
<> Values
d) (Mappings
b Mappings -> Mappings -> Mappings
forall a. Semigroup a => a -> a -> a
<> Mappings
e) (Prefixes
c Prefixes -> Prefixes -> Prefixes
forall a. Semigroup a => a -> a -> a
<> Prefixes
f)

instance Monoid RichEnv where
  mempty :: RichEnv
  mempty :: RichEnv
mempty = Values -> Mappings -> Prefixes -> RichEnv
RichEnv Values
forall a. Monoid a => a
mempty Mappings
forall a. Monoid a => a
mempty Prefixes
forall a. Monoid a => a
mempty

-- | Default 'RichEnv' value. With everything empty.
defaultRichEnv :: RichEnv
defaultRichEnv :: RichEnv
defaultRichEnv = RichEnv
forall a. Monoid a => a
mempty