{-# OPTIONS_GHC -Wall #-} {-# LANGUAGE FlexibleContexts #-} module Elm.Package.Solution (Solution, write, read) where import Prelude hiding (read) import Control.Monad.Error (MonadError, throwError, MonadIO, liftIO) import Data.Aeson import Data.Aeson.Encode.Pretty (encodePretty) import qualified Data.ByteString.Lazy as BS import qualified Data.HashMap.Strict as HashMap import qualified Data.Map as Map import qualified Data.Text as Text import qualified Elm.Package.Name as N import qualified Elm.Package.Version as V type Solution = Map.Map N.Name V.Version -- READING AND WRITING SOLUTIONS write :: FilePath -> Solution -> IO () write filePath solution = BS.writeFile filePath (encodePretty (toJson solution)) read :: (MonadIO m, MonadError String m) => FilePath -> m Solution read path = do rawJson <- liftIO (BS.readFile path) either throwCorrupted fromJson (eitherDecode rawJson) where throwCorrupted _msg = throwError $ "Unable to extract package information from the " ++ path ++ " file.\nIt may be corrupted." -- CONVERSION TO JSON toJson :: Solution -> Value toJson solution = object (map toField (Map.toList solution)) where toField (name, version) = Text.pack (N.toString name) .= Text.pack (V.toString version) fromJson :: (MonadError String m) => HashMap.HashMap String String -> m Solution fromJson hashMap = do pairs <- mapM parseNameAndVersion (HashMap.toList hashMap) return (Map.fromList pairs) parseNameAndVersion :: (MonadError String m) => (String,String) -> m (N.Name, V.Version) parseNameAndVersion (rawName, rawVersion) = do name <- parse rawName N.fromString ("package name " ++ rawName) vrsn <- parse rawVersion V.fromString ("version number for package " ++ rawName) return (name, vrsn) parse :: (MonadError String m) => String -> (String -> Maybe a) -> String -> m a parse string fromString msg = maybe (throwError ("Could not parse " ++ msg)) return (fromString string)