packages feed

dojang-0.1.0: src/Dojang/Types/FilePathExpression/Expansion.hs

module Dojang.Types.FilePathExpression.Expansion
  ( ExpansionWarning (..)
  , expandFilePath
  ) where

import Dojang.Types.FilePathExpression
  ( EnvironmentVariable
  , FilePathExpression (..)
  )

import Data.Text (Text)
import System.OsPath (OsPath, pack, pathSeparator, unsafeFromChar, (</>))
import System.OsString (OsString)


-- | A set of warnings that can occur during expansion.
newtype ExpansionWarning
  = -- | The case where an environment variable that is referenced in a
    -- 'Substitution' is not defined.
    UndefinedEnvironmentVariable EnvironmentVariable
  deriving (Eq, Show)


-- | Expands a 'FilePathExpression' into an 'OsPath'.
expandFilePath
  :: (Monad m)
  => FilePathExpression
  -- ^ The 'FilePathExpression' to expand.
  -> (EnvironmentVariable -> m (Maybe OsString))
  -- ^ A function that can look up an environment variable.
  -> (Text -> m OsString)
  -- ^ A function that encodes a 'Text' into an 'OsString'.
  -> m (OsPath, [ExpansionWarning])
  -- ^ The expanded 'OsPath', along with a list of warnings that occurred during
  -- expansion (if any).
expandFilePath (BareComponent component) _ encode = do
  f <- encode component
  return (f, [])
expandFilePath (Root Nothing) _ _ = return (pack [pathSeparator], [])
expandFilePath (Root (Just driveLetter)) _ _ =
  return
    ( pack
        [ unsafeFromChar driveLetter
        , unsafeFromChar ':'
        , pathSeparator
        ]
    , []
    )
expandFilePath (Concatenation expr1 expr2) lookupEnv encode = do
  (expanded1, ws1) <- expandFilePath expr1 lookupEnv encode
  (expanded2, ws2) <- expandFilePath expr2 lookupEnv encode
  return (expanded1 <> expanded2, ws1 ++ ws2)
expandFilePath (PathSeparator expr1 expr2) lookupEnv encode = do
  (expanded1, ws1) <- expandFilePath expr1 lookupEnv encode
  (expanded2, ws2) <- expandFilePath expr2 lookupEnv encode
  return (expanded1 </> expanded2, ws1 ++ ws2)
expandFilePath (Substitution envVar) lookupEnv _ = do
  v <- lookupEnv envVar
  case v of
    Just v' -> return (v', [])
    Nothing -> return (mempty, [UndefinedEnvironmentVariable envVar])
expandFilePath (SubstitutionWithDefault envVar expr) lookupEnv encode = do
  env <- lookupEnv envVar
  case env of
    Just env' | env' /= mempty -> return (env', [])
    _ -> expandFilePath expr lookupEnv encode
expandFilePath (ConditionalSubstitution envVar expr) lookupEnv encode = do
  env <- lookupEnv envVar
  case env of
    Just env' | env' /= mempty -> expandFilePath expr lookupEnv encode
    _ -> return (mempty, [])