    {-# LANGUAGE CPP #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE TypeFamilies #-}
    module Hpack.Syntax.Dependencies (
      Dependencies(..)
    , DependencyInfo(..)
    , parseDependency
    ) where

    import           Imports

    import qualified Control.Monad.Fail as Fail
    import qualified Data.Text as T
    import qualified Distribution.Package as D
    import qualified Distribution.Types.LibraryName as D
    import           Distribution.Pretty (prettyShow)
    import           Data.Map.Lazy (Map)
    import qualified Data.Map.Lazy as Map
    import           GHC.Exts

    #if MIN_VERSION_Cabal(3,4,0)
    import qualified Distribution.Compat.NonEmptySet as DependencySet
    #else
    import qualified Data.Set as DependencySet
    #endif

    import           Data.Aeson.Config.FromValue
    import           Data.Aeson.Config.Types

    import           Hpack.Syntax.DependencyVersion
    import           Hpack.Syntax.ParseDependencies

    newtype Dependencies = Dependencies {
      Dependencies -> Map String DependencyInfo
    unDependencies :: Map String DependencyInfo
    } deriving (Dependencies -> Dependencies -> Bool
    (Dependencies -> Dependencies -> Bool)
    -> (Dependencies -> Dependencies -> Bool) -> Eq Dependencies
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Dependencies -> Dependencies -> Bool
    == :: Dependencies -> Dependencies -> Bool
    $c/= :: Dependencies -> Dependencies -> Bool
    /= :: Dependencies -> Dependencies -> Bool
    Eq, Int -> Dependencies -> ShowS
    [Dependencies] -> ShowS
    Dependencies -> String
    (Int -> Dependencies -> ShowS)
    -> (Dependencies -> String)
    -> ([Dependencies] -> ShowS)
    -> Show Dependencies
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Dependencies -> ShowS
    showsPrec :: Int -> Dependencies -> ShowS
    $cshow :: Dependencies -> String
    show :: Dependencies -> String
    $cshowList :: [Dependencies] -> ShowS
    showList :: [Dependencies] -> ShowS
    Show, NonEmpty Dependencies -> Dependencies
    Dependencies -> Dependencies -> Dependencies
    (Dependencies -> Dependencies -> Dependencies)
    -> (NonEmpty Dependencies -> Dependencies)
    -> (forall b. Integral b => b -> Dependencies -> Dependencies)
    -> Semigroup Dependencies
    forall b. Integral b => b -> Dependencies -> Dependencies
    forall a.
    (a -> a -> a)
    -> (NonEmpty a -> a)
    -> (forall b. Integral b => b -> a -> a)
    -> Semigroup a
    $c<> :: Dependencies -> Dependencies -> Dependencies
    <> :: Dependencies -> Dependencies -> Dependencies
    $csconcat :: NonEmpty Dependencies -> Dependencies
    sconcat :: NonEmpty Dependencies -> Dependencies
    $cstimes :: forall b. Integral b => b -> Dependencies -> Dependencies
    stimes :: forall b. Integral b => b -> Dependencies -> Dependencies
    Semigroup, Semigroup Dependencies
    Dependencies
    Semigroup Dependencies =>
    Dependencies
    -> (Dependencies -> Dependencies -> Dependencies)
    -> ([Dependencies] -> Dependencies)
    -> Monoid Dependencies
    [Dependencies] -> Dependencies
    Dependencies -> Dependencies -> Dependencies
    forall a.
    Semigroup a =>
    a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
    $cmempty :: Dependencies
    mempty :: Dependencies
    $cmappend :: Dependencies -> Dependencies -> Dependencies
    mappend :: Dependencies -> Dependencies -> Dependencies
    $cmconcat :: [Dependencies] -> Dependencies
    mconcat :: [Dependencies] -> Dependencies
    Monoid)

    instance IsList Dependencies where
      type Item Dependencies = (String, DependencyInfo)
      fromList :: [Item Dependencies] -> Dependencies
    fromList = Map String DependencyInfo -> Dependencies
    Dependencies (Map String DependencyInfo -> Dependencies)
    -> ([(String, DependencyInfo)] -> Map String DependencyInfo)
    -> [(String, DependencyInfo)]
    -> Dependencies
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [(String, DependencyInfo)] -> Map String DependencyInfo
    forall k a. Ord k => [(k, a)] -> Map k a
    Map.fromList
      toList :: Dependencies -> [Item Dependencies]
    toList = Map String DependencyInfo -> [(String, DependencyInfo)]
    forall k a. Map k a -> [(k, a)]
    Map.toList (Map String DependencyInfo -> [(String, DependencyInfo)])
    -> (Dependencies -> Map String DependencyInfo)
    -> Dependencies
    -> [(String, DependencyInfo)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Dependencies -> Map String DependencyInfo
    unDependencies

    instance FromValue Dependencies where
      fromValue :: Value -> Parser Dependencies
    fromValue = ([(String, DependencyInfo)] -> Dependencies)
    -> Parser [(String, DependencyInfo)] -> Parser Dependencies
    forall a b. (a -> b) -> Parser a -> Parser b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Map String DependencyInfo -> Dependencies
    Dependencies (Map String DependencyInfo -> Dependencies)
    -> ([(String, DependencyInfo)] -> Map String DependencyInfo)
    -> [(String, DependencyInfo)]
    -> Dependencies
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [(String, DependencyInfo)] -> Map String DependencyInfo
    forall k a. Ord k => [(k, a)] -> Map k a
    Map.fromList) (Parser [(String, DependencyInfo)] -> Parser Dependencies)
    -> (Value -> Parser [(String, DependencyInfo)])
    -> Value
    -> Parser Dependencies
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Parse String DependencyInfo
    -> Value -> Parser [(String, DependencyInfo)]
    forall k v. Parse k v -> Value -> Parser [(k, v)]
    parseDependencies Parse String DependencyInfo
    parse
        where
          parse :: Parse String DependencyInfo
          parse :: Parse String DependencyInfo
    parse = Parse {
            parseString :: Text -> Parser (String, DependencyInfo)
    parseString = \ Text
    input -> do
              (String
    name, DependencyVersion
    version) <- String -> Text -> Parser (String, DependencyVersion)
    forall (m :: * -> *).
    MonadFail m =>
    String -> Text -> m (String, DependencyVersion)
    parseDependency String
    "dependency" Text
    input
              (String, DependencyInfo) -> Parser (String, DependencyInfo)
    forall a. a -> Parser a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String
    name, [String] -> DependencyVersion -> DependencyInfo
    DependencyInfo [] DependencyVersion
    version)
          , parseListItem :: Object -> Parser DependencyInfo
    parseListItem = Object -> Parser DependencyInfo
    objectDependencyInfo
          , parseDictItem :: Value -> Parser DependencyInfo
    parseDictItem = Value -> Parser DependencyInfo
    dependencyInfo
          , parseName :: Text -> String
    parseName = Text -> String
    T.unpack
          }

    data DependencyInfo = DependencyInfo {
      DependencyInfo -> [String]
    dependencyInfoMixins :: [String]
    , DependencyInfo -> DependencyVersion
    dependencyInfoVersion :: DependencyVersion
    } deriving (DependencyInfo -> DependencyInfo -> Bool
    (DependencyInfo -> DependencyInfo -> Bool)
    -> (DependencyInfo -> DependencyInfo -> Bool) -> Eq DependencyInfo
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: DependencyInfo -> DependencyInfo -> Bool
    == :: DependencyInfo -> DependencyInfo -> Bool
    $c/= :: DependencyInfo -> DependencyInfo -> Bool
    /= :: DependencyInfo -> DependencyInfo -> Bool
    Eq, Eq DependencyInfo
    Eq DependencyInfo =>
    (DependencyInfo -> DependencyInfo -> Ordering)
    -> (DependencyInfo -> DependencyInfo -> Bool)
    -> (DependencyInfo -> DependencyInfo -> Bool)
    -> (DependencyInfo -> DependencyInfo -> Bool)
    -> (DependencyInfo -> DependencyInfo -> Bool)
    -> (DependencyInfo -> DependencyInfo -> DependencyInfo)
    -> (DependencyInfo -> DependencyInfo -> DependencyInfo)
    -> Ord DependencyInfo
    DependencyInfo -> DependencyInfo -> Bool
    DependencyInfo -> DependencyInfo -> Ordering
    DependencyInfo -> DependencyInfo -> DependencyInfo
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: DependencyInfo -> DependencyInfo -> Ordering
    compare :: DependencyInfo -> DependencyInfo -> Ordering
    $c< :: DependencyInfo -> DependencyInfo -> Bool
    < :: DependencyInfo -> DependencyInfo -> Bool
    $c<= :: DependencyInfo -> DependencyInfo -> Bool
    <= :: DependencyInfo -> DependencyInfo -> Bool
    $c> :: DependencyInfo -> DependencyInfo -> Bool
    > :: DependencyInfo -> DependencyInfo -> Bool
    $c>= :: DependencyInfo -> DependencyInfo -> Bool
    >= :: DependencyInfo -> DependencyInfo -> Bool
    $cmax :: DependencyInfo -> DependencyInfo -> DependencyInfo
    max :: DependencyInfo -> DependencyInfo -> DependencyInfo
    $cmin :: DependencyInfo -> DependencyInfo -> DependencyInfo
    min :: DependencyInfo -> DependencyInfo -> DependencyInfo
    Ord, Int -> DependencyInfo -> ShowS
    [DependencyInfo] -> ShowS
    DependencyInfo -> String
    (Int -> DependencyInfo -> ShowS)
    -> (DependencyInfo -> String)
    -> ([DependencyInfo] -> ShowS)
    -> Show DependencyInfo
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> DependencyInfo -> ShowS
    showsPrec :: Int -> DependencyInfo -> ShowS
    $cshow :: DependencyInfo -> String
    show :: DependencyInfo -> String
    $cshowList :: [DependencyInfo] -> ShowS
    showList :: [DependencyInfo] -> ShowS
    Show)

    addMixins :: Object -> DependencyVersion -> Parser DependencyInfo
    addMixins :: Object -> DependencyVersion -> Parser DependencyInfo
    addMixins Object
    o DependencyVersion
    version = do
      Maybe (List String)
    mixinsMay <- Object
    o Object -> Key -> Parser (Maybe (List String))
    forall a. FromValue a => Object -> Key -> Parser (Maybe a)
    .:? Key
    "mixin"
      DependencyInfo -> Parser DependencyInfo
    forall a. a -> Parser a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (DependencyInfo -> Parser DependencyInfo)
    -> DependencyInfo -> Parser DependencyInfo
    forall a b. (a -> b) -> a -> b
    $ [String] -> DependencyVersion -> DependencyInfo
    DependencyInfo (Maybe (List String) -> [String]
    forall a. Maybe (List a) -> [a]
    fromMaybeList Maybe (List String)
    mixinsMay) DependencyVersion
    version

    objectDependencyInfo :: Object -> Parser DependencyInfo
    objectDependencyInfo :: Object -> Parser DependencyInfo
    objectDependencyInfo Object
    o = Object -> Parser DependencyVersion
    objectDependency Object
    o Parser DependencyVersion
    -> (DependencyVersion -> Parser DependencyInfo)
    -> Parser DependencyInfo
    forall a b. Parser a -> (a -> Parser b) -> Parser b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Object -> DependencyVersion -> Parser DependencyInfo
    addMixins Object
    o

    dependencyInfo :: Value -> Parser DependencyInfo
    dependencyInfo :: Value -> Parser DependencyInfo
    dependencyInfo = (DependencyVersion -> DependencyInfo)
    -> (Object -> DependencyVersion -> Parser DependencyInfo)
    -> Value
    -> Parser DependencyInfo
    forall a.
    (DependencyVersion -> a)
    -> (Object -> DependencyVersion -> Parser a) -> Value -> Parser a
    withDependencyVersion ([String] -> DependencyVersion -> DependencyInfo
    DependencyInfo []) Object -> DependencyVersion -> Parser DependencyInfo
    addMixins

    parseDependency :: Fail.MonadFail m => String -> Text -> m (String, DependencyVersion)
    parseDependency :: forall (m :: * -> *).
    MonadFail m =>
    String -> Text -> m (String, DependencyVersion)
    parseDependency String
    subject = (Dependency -> (String, DependencyVersion))
    -> m Dependency -> m (String, DependencyVersion)
    forall a b. (a -> b) -> m a -> m b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Dependency -> (String, DependencyVersion)
    fromCabal (m Dependency -> m (String, DependencyVersion))
    -> (Text -> m Dependency) -> Text -> m (String, DependencyVersion)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> String -> m Dependency
    forall (m :: * -> *) a.
    (MonadFail m, Parsec a) =>
    String -> String -> m a
    cabalParse String
    subject (String -> m Dependency)
    -> (Text -> String) -> Text -> m Dependency
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack
      where
        fromCabal :: D.Dependency -> (String, DependencyVersion)
        fromCabal :: Dependency -> (String, DependencyVersion)
    fromCabal Dependency
    d = (PackageName -> [LibraryName] -> String
    toName (Dependency -> PackageName
    D.depPkgName Dependency
    d) (NonEmptySet LibraryName -> [LibraryName]
    forall a. NonEmptySet a -> [a]
    DependencySet.toList (NonEmptySet LibraryName -> [LibraryName])
    -> NonEmptySet LibraryName -> [LibraryName]
    forall a b. (a -> b) -> a -> b
    $ Dependency -> NonEmptySet LibraryName
    D.depLibraries Dependency
    d), Maybe SourceDependency -> VersionConstraint -> DependencyVersion
    DependencyVersion Maybe SourceDependency
    forall a. Maybe a
    Nothing (VersionConstraint -> DependencyVersion)
    -> (VersionRange -> VersionConstraint)
    -> VersionRange
    -> DependencyVersion
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . VersionRange -> VersionConstraint
    versionConstraintFromCabal (VersionRange -> DependencyVersion)
    -> VersionRange -> DependencyVersion
    forall a b. (a -> b) -> a -> b
    $ Dependency -> VersionRange
    D.depVerRange Dependency
    d)

        toName :: D.PackageName -> [D.LibraryName] -> String
        toName :: PackageName -> [LibraryName] -> String
    toName PackageName
    package [LibraryName]
    components = PackageName -> String
    forall a. Pretty a => a -> String
    prettyShow PackageName
    package String -> ShowS
    forall a. Semigroup a => a -> a -> a
    <> case [LibraryName]
    components of
          [LibraryName
    D.LMainLibName] -> String
    ""
          [D.LSubLibName UnqualComponentName
    lib] -> String
    ":" String -> ShowS
    forall a. Semigroup a => a -> a -> a
    <> UnqualComponentName -> String
    forall a. Pretty a => a -> String
    prettyShow UnqualComponentName
    lib
          [LibraryName]
    xs -> String
    ":{" String -> ShowS
    forall a. Semigroup a => a -> a -> a
    <> (String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    "," ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ (UnqualComponentName -> String)
    -> [UnqualComponentName] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map UnqualComponentName -> String
    forall a. Pretty a => a -> String
    prettyShow [UnqualComponentName
    name | D.LSubLibName UnqualComponentName
    name <- [LibraryName]
    xs]) String -> ShowS
    forall a. Semigroup a => a -> a -> a
    <> String
    "}"