content: {-# LANGUAGE NoImplicitPrelude   #-}
  {-# LANGUAGE NoFieldSelectors    #-}
  {-# LANGUAGE OverloadedRecordDot #-}
  {-# LANGUAGE OverloadedStrings   #-}
  
  {-|
  Module      : Stack.Types.Project
  License     : BSD-3-Clause
  -}
  
  module Stack.Types.Project
    ( Project (..)
    ) where
  
  import           Data.Aeson.Types ( ToJSON (..), (.=), object )
  import qualified Data.Map as Map
  import qualified Data.Set as Set
  import           Stack.Prelude
  import           Stack.Types.Curator ( Curator )
  
  -- | A project is a collection of packages. We can have multiple stack.yaml
  -- files, but only one of them may contain project information.
  data Project = Project
    { userMsg :: !(Maybe String)
      -- ^ A warning message to display to the user when the auto generated
      -- config may have issues.
    , packages :: ![RelFilePath]
      -- ^ Packages which are actually part of the project (as opposed
      -- to dependencies).
    , extraDeps :: ![RawPackageLocation]
      -- ^ Dependencies defined within the stack.yaml file, to be applied on top
      -- of the snapshot.
    , flagsByPkg :: !(Map PackageName (Map FlagName Bool))
      -- ^ Flags to be applied on top of the snapshot flags.
    , snapshot :: !RawSnapshotLocation
      -- ^ How we resolve which @Snapshot@ to use
    , compiler :: !(Maybe WantedCompiler)
      -- ^ Override the compiler in 'snapshot'
    , extraPackageDBs :: ![FilePath]
    , curator :: !(Maybe Curator)
      -- ^ Extra configuration intended exclusively for usage by the curator tool.
      -- In other words, this is /not/ part of the documented and exposed Stack
      -- API. SUBJECT TO CHANGE.
    , dropPackages :: !(Set PackageName)
      -- ^ Packages to drop from the 'snapshot'.
    }
    deriving Show
  
  instance ToJSON Project where
    -- Expanding the constructor fully to ensure we don't miss any fields.
    toJSON project = object $ concat
      [ maybe [] (\cv -> ["compiler" .= cv]) project.compiler
      , maybe [] (\msg -> ["user-message" .= msg]) project.userMsg
      , [ "extra-package-dbs" .= project.extraPackageDBs
        | not (null project.extraPackageDBs)
        ]
      , [ "extra-deps" .= project.extraDeps | not (null project.extraDeps) ]
      , [ "flags" .= fmap toCabalStringMap (toCabalStringMap project.flagsByPkg)
        | not (Map.null project.flagsByPkg)
        ]
      , ["packages" .= project.packages]
      , ["snapshot" .= project.snapshot]
      , maybe [] (\c -> ["curator" .= c]) project.curator
      , [ "drop-packages" .= Set.map CabalString project.dropPackages
        | not (Set.null project.dropPackages)
        ]
      ]
  