module Hix.Data.Dep where

import Data.Aeson (FromJSON (parseJSON), Value (Object, String), (.:))
import Data.Aeson.Types (Parser)
import Distribution.Package (mainLibSet)
import Distribution.Pretty (Pretty, pretty)
import Distribution.Types.Dependency (Dependency (Dependency))
import Distribution.Version (VersionRange, thisVersion)
import Exon (exon)

import Hix.Data.Json (aesonParsec, jsonParsec)
import qualified Hix.Data.PackageName as PackageName
import Hix.Data.PackageName (PackageName)
import Hix.Data.Version (Version)

data Dep =
  Dep {
    Dep -> PackageName
package :: PackageName,
    Dep -> VersionRange
version :: VersionRange
  }
  deriving stock (Dep -> Dep -> Bool
(Dep -> Dep -> Bool) -> (Dep -> Dep -> Bool) -> Eq Dep
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Dep -> Dep -> Bool
== :: Dep -> Dep -> Bool
$c/= :: Dep -> Dep -> Bool
/= :: Dep -> Dep -> Bool
Eq, Int -> Dep -> ShowS
[Dep] -> ShowS
Dep -> String
(Int -> Dep -> ShowS)
-> (Dep -> String) -> ([Dep] -> ShowS) -> Show Dep
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Dep -> ShowS
showsPrec :: Int -> Dep -> ShowS
$cshow :: Dep -> String
show :: Dep -> String
$cshowList :: [Dep] -> ShowS
showList :: [Dep] -> ShowS
Show, (forall x. Dep -> Rep Dep x)
-> (forall x. Rep Dep x -> Dep) -> Generic Dep
forall x. Rep Dep x -> Dep
forall x. Dep -> Rep Dep x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Dep -> Rep Dep x
from :: forall x. Dep -> Rep Dep x
$cto :: forall x. Rep Dep x -> Dep
to :: forall x. Rep Dep x -> Dep
Generic)

toCabal :: Dep -> Dependency
toCabal :: Dep -> Dependency
toCabal Dep {VersionRange
PackageName
package :: Dep -> PackageName
version :: Dep -> VersionRange
package :: PackageName
version :: VersionRange
..} =
  PackageName
-> VersionRange -> NonEmptySet LibraryName -> Dependency
Dependency (PackageName -> PackageName
PackageName.toCabal PackageName
package) VersionRange
version NonEmptySet LibraryName
mainLibSet

fromCabal :: Dependency -> Dep
fromCabal :: Dependency -> Dep
fromCabal (Dependency (PackageName -> PackageName
PackageName.fromCabal -> PackageName
package) VersionRange
version NonEmptySet LibraryName
_) =
  Dep {PackageName
package :: PackageName
package :: PackageName
package, VersionRange
version :: VersionRange
version :: VersionRange
version}

instance Pretty Dep where
  pretty :: Dep -> Doc
pretty = Dependency -> Doc
forall a. Pretty a => a -> Doc
pretty (Dependency -> Doc) -> (Dep -> Dependency) -> Dep -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dep -> Dependency
toCabal

mkDep :: PackageName -> VersionRange -> Dep
mkDep :: PackageName -> VersionRange -> Dep
mkDep PackageName
package VersionRange
version = Dep {VersionRange
PackageName
package :: PackageName
version :: VersionRange
package :: PackageName
version :: VersionRange
..}

jsonParseCabal :: String -> Parser Dep
jsonParseCabal :: String -> Parser Dep
jsonParseCabal String
v = Dependency -> Dep
fromCabal (Dependency -> Dep) -> Parser Dependency -> Parser Dep
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> Parser Dependency
forall a. Parsec a => String -> Parser a
aesonParsec String
v

renderDep :: Dep -> Text
renderDep :: Dep -> Text
renderDep = Doc -> Text
forall b a. (Show a, IsString b) => a -> b
show (Doc -> Text) -> (Dep -> Doc) -> Dep -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dep -> Doc
forall a. Pretty a => a -> Doc
pretty

thisVersionDep :: PackageName -> Version -> Dep
thisVersionDep :: PackageName -> Version -> Dep
thisVersionDep PackageName
package Version
version =
  PackageName -> VersionRange -> Dep
mkDep PackageName
package (Version -> VersionRange
thisVersion Version
version)

instance FromJSON Dep where
  parseJSON :: Value -> Parser Dep
parseJSON = \case
    String Text
s ->
      String -> Parser Dep
jsonParseCabal (Text -> String
forall a. ToString a => a -> String
toString Text
s)
    Object Object
o -> do
      Dep
fromName <- String -> Parser Dep
jsonParseCabal (String -> Parser Dep) -> Parser String -> Parser Dep
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Object
o Object -> Key -> Parser String
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"name"
      VersionRange
version <- (JsonParsec VersionRange -> VersionRange
forall a. JsonParsec a -> a
jsonParsec (JsonParsec VersionRange -> VersionRange)
-> Parser (JsonParsec VersionRange) -> Parser VersionRange
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Key -> Parser (JsonParsec VersionRange)
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"version") Parser VersionRange -> Parser VersionRange -> Parser VersionRange
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> VersionRange -> Parser VersionRange
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Dep
fromName.version
      pure Dep
fromName {version}
    Value
v ->
      String -> Parser Dep
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail [exon|Invalid dependency format: #{show v}|]

withVersion :: VersionRange -> Dep -> Dep
withVersion :: VersionRange -> Dep -> Dep
withVersion VersionRange
version Dep
dep = Dep
dep {version}