content: {-# LANGUAGE NoImplicitPrelude #-}
  -- | Configuring the compiler
  module Fay.Config
    ( Config
        ( configOptimize
        , configFlattenApps
        , configExportRuntime
        , configExportStdlib
        , configExportStdlibOnly
        , configPrettyPrint
        , configHtmlWrapper
        , configSourceMap
        , configHtmlJSLibs
        , configLibrary
        , configWarn
        , configFilePath
        , configTypecheck
        , configWall
        , configGClosure
        , configPackageConf
        , configBasePath
        , configStrict
        , configTypecheckOnly
        , configRuntimePath
        , configOptimizeNewtypes
        , configPrettyThunks
        , configPrettyOperators
        , configShowGhcCalls
        , configTypeScript
        )
    , defaultConfig
    , defaultConfigWithSandbox
    , configDirectoryIncludes
    , configDirectoryIncludePaths
    , nonPackageConfigDirectoryIncludePaths
    , addConfigDirectoryInclude
    , addConfigDirectoryIncludes
    , addConfigDirectoryIncludePaths
    , configPackages
    , addConfigPackage
    , addConfigPackages
    , shouldExportStrictWrapper
    ) where
  
  import           Fay.Compiler.Prelude
  
  import           Data.Default
  import           Data.Maybe                      ()
  import           Language.Haskell.Exts (ModuleName (..))
  import           System.Environment
  
  -- | Configuration of the compiler.
  -- The fields with a leading underscore
  data Config = Config
    { configOptimize           :: Bool                        -- ^ Run optimizations
    , configFlattenApps        :: Bool                        -- ^ Flatten function application?
    , configExportRuntime      :: Bool                        -- ^ Export the runtime?
    , configExportStdlib       :: Bool                        -- ^ Export the stdlib?
    , configExportStdlibOnly   :: Bool                        -- ^ Export /only/ the stdlib?
    , _configDirectoryIncludes :: [(Maybe String, FilePath)]  -- ^ Possibly a fay package name, and a include directory.
    , configPrettyPrint        :: Bool                        -- ^ Pretty print the JS output?
    , configHtmlWrapper        :: Bool                        -- ^ Output a HTML file including the produced JS.
    , configSourceMap          :: Bool                        -- ^ Output a source map file as outfile.map.
    , configHtmlJSLibs         :: [FilePath]                  -- ^ Any JS files to link to in the HTML.
    , configLibrary            :: Bool                        -- ^ Don't invoke main in the produced JS.
    , configWarn               :: Bool                        -- ^ Warn on dubious stuff, not related to typechecking.
    , configFilePath           :: Maybe FilePath              -- ^ File path to output to.
    , configTypecheck          :: Bool                        -- ^ Typecheck with GHC.
    , configWall               :: Bool                        -- ^ Typecheck with -Wall.
    , configGClosure           :: Bool                        -- ^ Run Google Closure on the produced JS.
    , configPackageConf        :: Maybe FilePath              -- ^ The package config e.g. packages-6.12.3.
    , _configPackages          :: [String]                    -- ^ Included Fay packages.
    , configBasePath           :: Maybe FilePath              -- ^ Custom source location for fay-base
    , configStrict             :: [String]                    -- ^ Produce strict and uncurried JavaScript callable wrappers for all
                                                              --   exported functions with type signatures in the given module
    , configTypecheckOnly      :: Bool                        -- ^ Only invoke GHC for typechecking, don't produce any output
    , configRuntimePath        :: Maybe FilePath
    , configOptimizeNewtypes   :: Bool                        -- ^ Optimize away newtype constructors?
    , configPrettyThunks       :: Bool                        -- ^ Use pretty thunk names?
    , configPrettyOperators    :: Bool                        -- ^ Use pretty operators?
    , configShowGhcCalls       :: Bool                        -- ^ Print commands sent to GHC?
    , configTypeScript         :: Bool                        -- ^ Output a TypeScript file.
    } deriving (Show)
  
  defaultConfig :: Config
  defaultConfig = addConfigPackage "fay-base"
    Config
      { configOptimize           = False
      , configFlattenApps        = False
      , configExportRuntime      = True
      , configExportStdlib       = True
      , configExportStdlibOnly   = False
      , _configDirectoryIncludes = []
      , configPrettyPrint        = False
      , configHtmlWrapper        = False
      , configHtmlJSLibs         = []
      , configLibrary            = False
      , configWarn               = True
      , configFilePath           = Nothing
      , configTypecheck          = True
      , configWall               = False
      , configGClosure           = False
      , configPackageConf        = Nothing
      , _configPackages          = []
      , configBasePath           = Nothing
      , configStrict             = []
      , configTypecheckOnly      = False
      , configRuntimePath        = Nothing
      , configSourceMap          = False
      , configOptimizeNewtypes   = True
      , configPrettyThunks       = False
      , configPrettyOperators    = False
      , configShowGhcCalls       = False
      , configTypeScript         = False
      }
  
  defaultConfigWithSandbox :: IO Config
  defaultConfigWithSandbox = do
    packageConf <- fmap (lookup "HASKELL_PACKAGE_SANDBOX") getEnvironment
    return defaultConfig { configPackageConf = packageConf }
  
  -- | Default configuration.
  instance Default Config where
    def = defaultConfig
  
  -- | Reading _configDirectoryIncludes is safe to do.
  configDirectoryIncludes :: Config -> [(Maybe String, FilePath)]
  configDirectoryIncludes = _configDirectoryIncludes
  
  -- | Get all include directories without the package mapping.
  configDirectoryIncludePaths :: Config -> [FilePath]
  configDirectoryIncludePaths = map snd . _configDirectoryIncludes
  
  -- | Get all include directories not included through packages.
  nonPackageConfigDirectoryIncludePaths :: Config -> [FilePath]
  nonPackageConfigDirectoryIncludePaths = map snd . filter (isJust . fst) . _configDirectoryIncludes
  
  -- | Add a mapping from (maybe) a package to a source directory
  addConfigDirectoryInclude :: Maybe String -> FilePath -> Config -> Config
  addConfigDirectoryInclude pkg fp cfg = cfg { _configDirectoryIncludes = (pkg, fp) : _configDirectoryIncludes cfg }
  
  -- | Add several include directories.
  addConfigDirectoryIncludes :: [(Maybe String,FilePath)] -> Config -> Config
  addConfigDirectoryIncludes pkgFps cfg = foldl (\c (pkg,fp) -> addConfigDirectoryInclude pkg fp c) cfg pkgFps
  
  -- | Add several include directories without package references.
  addConfigDirectoryIncludePaths :: [FilePath] -> Config -> Config
  addConfigDirectoryIncludePaths fps cfg = foldl (flip (addConfigDirectoryInclude Nothing)) cfg fps
  
  -- | Reading _configPackages is safe to do.
  configPackages :: Config -> [String]
  configPackages = _configPackages
  
  -- | Add a package to compilation
  addConfigPackage :: String -> Config -> Config
  addConfigPackage pkg cfg = cfg { _configPackages = pkg : _configPackages cfg }
  
  -- | Add several packages to compilation
  addConfigPackages :: [String] -> Config -> Config
  addConfigPackages fps cfg = foldl (flip addConfigPackage) cfg fps
  
  
  -- | Should a strict wrapper be generated for this module?
  shouldExportStrictWrapper :: ModuleName a -> Config -> Bool
  shouldExportStrictWrapper (ModuleName _ m) cs = m `elem` configStrict cs
  