{- |
Copyright: (c) 2020-2022 Kowainik
SPDX-License-Identifier: MPL-2.0
Maintainer: Kowainik <xrom.xkov@gmail.com>

Parse Haskell Language Extensions.
-}

module Extensions.Package
       ( -- * Package modules
         getPackageExtentions
       , getPackageExtentionsBySources

         -- * Single module
       , getModuleAndCabalExtentions
       , getModuleExtentions
       , getModuleAndCabalExtentionsBySource
       , getModuleExtentionsBySource
       ) where

import Control.Exception (catch)
import Data.ByteString (ByteString)
import Data.Functor ((<&>))
import Data.Map.Merge.Strict (mapMissing, merge, zipWithMatched)
import Data.Map.Strict (Map)

import Extensions.Cabal (parseCabalFileExtensions)
import Extensions.Module (parseFile, parseSourceWithPath)
import Extensions.Types (CabalAndModuleExtensions (..), CabalException, ExtensionsError (..),
                         ExtensionsResult, ModuleParseError, ParsedExtensions (..),
                         mergeAnyExtensions)

import qualified Data.Map.Strict as Map


{- | By given path to @.cabal@ file, analyse extensions for each Haskell module
and return the corresponding 'Map' with 'ExtensionsResult's.

__Throws__:

* 'CabalException'
-}
getPackageExtentions
    :: FilePath  -- ^ Path to @.cabal@ file.
    -> IO (Map FilePath ExtensionsResult)
getPackageExtentions :: FilePath -> IO (Map FilePath ExtensionsResult)
getPackageExtentions FilePath
cabalFile = do
    Map FilePath ParsedExtensions
cabalMap <- FilePath -> IO (Map FilePath ParsedExtensions)
parseCabalFileExtensions FilePath
cabalFile
    (FilePath -> ParsedExtensions -> IO ExtensionsResult)
-> Map FilePath ParsedExtensions
-> IO (Map FilePath ExtensionsResult)
forall (t :: * -> *) k a b.
Applicative t =>
(k -> a -> t b) -> Map k a -> t (Map k b)
Map.traverseWithKey FilePath -> ParsedExtensions -> IO ExtensionsResult
perModuleParseMerge Map FilePath ParsedExtensions
cabalMap
  where
    perModuleParseMerge :: FilePath -> ParsedExtensions -> IO ExtensionsResult
    perModuleParseMerge :: FilePath -> ParsedExtensions -> IO ExtensionsResult
perModuleParseMerge FilePath
path ParsedExtensions
cabalExts = do
        Either ModuleParseError ParsedExtensions
moduleRes <- FilePath -> IO (Either ModuleParseError ParsedExtensions)
parseFile FilePath
path
        ExtensionsResult -> IO ExtensionsResult
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExtensionsResult -> IO ExtensionsResult)
-> ExtensionsResult -> IO ExtensionsResult
forall a b. (a -> b) -> a -> b
$ ParsedExtensions
-> FilePath
-> Either ModuleParseError ParsedExtensions
-> ExtensionsResult
mergeCabalAndModule ParsedExtensions
cabalExts FilePath
path Either ModuleParseError ParsedExtensions
moduleRes

{- | By given path to @.cabal@ file and 'Map' of sources of all Haskell
modules, analyse extensions for each Haskell module and return the corresponding
'Map' with 'ExtensionsResult's.
-}
getPackageExtentionsBySources
    :: FilePath  -- ^ Path to @.cabal@ file.
    -> Map FilePath ByteString  -- ^ Path to modules with corresponding sources.
    -> IO (Map FilePath ExtensionsResult)
getPackageExtentionsBySources :: FilePath
-> Map FilePath ByteString -> IO (Map FilePath ExtensionsResult)
getPackageExtentionsBySources FilePath
cabalFile Map FilePath ByteString
sourcesMap =
    FilePath
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
parseCabalHandleException FilePath
cabalFile IO (Either ExtensionsError (Map FilePath ParsedExtensions))
-> (Either ExtensionsError (Map FilePath ParsedExtensions)
    -> Map FilePath ExtensionsResult)
-> IO (Map FilePath ExtensionsResult)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
        Left ExtensionsError
err -> ExtensionsError -> ExtensionsResult
forall a b. a -> Either a b
Left ExtensionsError
err ExtensionsResult
-> Map FilePath ByteString -> Map FilePath ExtensionsResult
forall a b. a -> Map FilePath b -> Map FilePath a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Map FilePath ByteString
sourcesMap
        Right Map FilePath ParsedExtensions
cabalMap -> SimpleWhenMissing FilePath ParsedExtensions ExtensionsResult
-> SimpleWhenMissing FilePath ByteString ExtensionsResult
-> SimpleWhenMatched
     FilePath ParsedExtensions ByteString ExtensionsResult
-> Map FilePath ParsedExtensions
-> Map FilePath ByteString
-> Map FilePath ExtensionsResult
forall k a c b.
Ord k =>
SimpleWhenMissing k a c
-> SimpleWhenMissing k b c
-> SimpleWhenMatched k a b c
-> Map k a
-> Map k b
-> Map k c
merge
            ((FilePath -> ParsedExtensions -> ExtensionsResult)
-> SimpleWhenMissing FilePath ParsedExtensions ExtensionsResult
forall (f :: * -> *) k x y.
Applicative f =>
(k -> x -> y) -> WhenMissing f k x y
mapMissing FilePath -> ParsedExtensions -> ExtensionsResult
cabalNotSource) -- in cabal but not in sources
            ((FilePath -> ByteString -> ExtensionsResult)
-> SimpleWhenMissing FilePath ByteString ExtensionsResult
forall (f :: * -> *) k x y.
Applicative f =>
(k -> x -> y) -> WhenMissing f k x y
mapMissing FilePath -> ByteString -> ExtensionsResult
sourceNotCabal) -- in sources but not in cabal
            ((FilePath -> ParsedExtensions -> ByteString -> ExtensionsResult)
-> SimpleWhenMatched
     FilePath ParsedExtensions ByteString ExtensionsResult
forall (f :: * -> *) k x y z.
Applicative f =>
(k -> x -> y -> z) -> WhenMatched f k x y z
zipWithMatched FilePath -> ParsedExtensions -> ByteString -> ExtensionsResult
cabalAndSource) -- in cabal and sources
            Map FilePath ParsedExtensions
cabalMap
            Map FilePath ByteString
sourcesMap
  where
    cabalNotSource :: FilePath -> ParsedExtensions -> ExtensionsResult
    cabalNotSource :: FilePath -> ParsedExtensions -> ExtensionsResult
cabalNotSource FilePath
path ParsedExtensions
_cabalExts = ExtensionsError -> ExtensionsResult
forall a b. a -> Either a b
Left (ExtensionsError -> ExtensionsResult)
-> ExtensionsError -> ExtensionsResult
forall a b. (a -> b) -> a -> b
$ FilePath -> ExtensionsError
SourceNotFound FilePath
path

    sourceNotCabal :: FilePath -> ByteString -> ExtensionsResult
    sourceNotCabal :: FilePath -> ByteString -> ExtensionsResult
sourceNotCabal FilePath
path ByteString
_source = ExtensionsError -> ExtensionsResult
forall a b. a -> Either a b
Left (ExtensionsError -> ExtensionsResult)
-> ExtensionsError -> ExtensionsResult
forall a b. (a -> b) -> a -> b
$ FilePath -> ExtensionsError
NotCabalModule FilePath
path

    cabalAndSource
        :: FilePath
        -> ParsedExtensions
        -> ByteString
        -> ExtensionsResult
    cabalAndSource :: FilePath -> ParsedExtensions -> ByteString -> ExtensionsResult
cabalAndSource FilePath
path ParsedExtensions
cabalExts ByteString
source =
        ParsedExtensions
-> FilePath
-> Either ModuleParseError ParsedExtensions
-> ExtensionsResult
mergeCabalAndModule ParsedExtensions
cabalExts FilePath
path (Either ModuleParseError ParsedExtensions -> ExtensionsResult)
-> Either ModuleParseError ParsedExtensions -> ExtensionsResult
forall a b. (a -> b) -> a -> b
$ FilePath -> ByteString -> Either ModuleParseError ParsedExtensions
parseSourceWithPath FilePath
path ByteString
source

{- | By given path to @.cabal@ file and path to Haskell module of the
corresponding package, analyse and return extensions for the
given module separately from .cabal file and from the module itself.
-}
getModuleAndCabalExtentions
    :: FilePath  -- ^ Path to @.cabal@ file.
    -> FilePath  -- ^ Path to Haskell module file.
    -> IO (Either ExtensionsError CabalAndModuleExtensions)
getModuleAndCabalExtentions :: FilePath
-> FilePath -> IO (Either ExtensionsError CabalAndModuleExtensions)
getModuleAndCabalExtentions FilePath
cabalFile FilePath
path =
    FilePath
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
parseCabalHandleException FilePath
cabalFile IO (Either ExtensionsError (Map FilePath ParsedExtensions))
-> (Either ExtensionsError (Map FilePath ParsedExtensions)
    -> IO (Either ExtensionsError CabalAndModuleExtensions))
-> IO (Either ExtensionsError CabalAndModuleExtensions)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Left ExtensionsError
err -> Either ExtensionsError CabalAndModuleExtensions
-> IO (Either ExtensionsError CabalAndModuleExtensions)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ExtensionsError CabalAndModuleExtensions
 -> IO (Either ExtensionsError CabalAndModuleExtensions))
-> Either ExtensionsError CabalAndModuleExtensions
-> IO (Either ExtensionsError CabalAndModuleExtensions)
forall a b. (a -> b) -> a -> b
$ ExtensionsError -> Either ExtensionsError CabalAndModuleExtensions
forall a b. a -> Either a b
Left ExtensionsError
err
        Right Map FilePath ParsedExtensions
cabalMap -> case FilePath -> Map FilePath ParsedExtensions -> Maybe ParsedExtensions
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
path Map FilePath ParsedExtensions
cabalMap of
            Maybe ParsedExtensions
Nothing        -> Either ExtensionsError CabalAndModuleExtensions
-> IO (Either ExtensionsError CabalAndModuleExtensions)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ExtensionsError CabalAndModuleExtensions
 -> IO (Either ExtensionsError CabalAndModuleExtensions))
-> Either ExtensionsError CabalAndModuleExtensions
-> IO (Either ExtensionsError CabalAndModuleExtensions)
forall a b. (a -> b) -> a -> b
$ ExtensionsError -> Either ExtensionsError CabalAndModuleExtensions
forall a b. a -> Either a b
Left (ExtensionsError
 -> Either ExtensionsError CabalAndModuleExtensions)
-> ExtensionsError
-> Either ExtensionsError CabalAndModuleExtensions
forall a b. (a -> b) -> a -> b
$ FilePath -> ExtensionsError
NotCabalModule FilePath
path
            Just ParsedExtensions
cabalExts -> FilePath
-> ParsedExtensions
-> Either ModuleParseError ParsedExtensions
-> Either ExtensionsError CabalAndModuleExtensions
getCabalAndModuleExts FilePath
path ParsedExtensions
cabalExts (Either ModuleParseError ParsedExtensions
 -> Either ExtensionsError CabalAndModuleExtensions)
-> IO (Either ModuleParseError ParsedExtensions)
-> IO (Either ExtensionsError CabalAndModuleExtensions)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> IO (Either ModuleParseError ParsedExtensions)
parseFile FilePath
path

{- | By given path to @.cabal@ file and path to Haskell module of the
corresponding package, analyse and return summary set of extensions for the
given module.
-}
getModuleExtentions
    :: FilePath  -- ^ Path to @.cabal@ file.
    -> FilePath  -- ^ Path to Haskell module file.
    -> IO ExtensionsResult
getModuleExtentions :: FilePath -> FilePath -> IO ExtensionsResult
getModuleExtentions FilePath
cabalFile FilePath
path =
    FilePath
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
parseCabalHandleException FilePath
cabalFile IO (Either ExtensionsError (Map FilePath ParsedExtensions))
-> (Either ExtensionsError (Map FilePath ParsedExtensions)
    -> IO ExtensionsResult)
-> IO ExtensionsResult
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Left ExtensionsError
err -> ExtensionsResult -> IO ExtensionsResult
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExtensionsResult -> IO ExtensionsResult)
-> ExtensionsResult -> IO ExtensionsResult
forall a b. (a -> b) -> a -> b
$ ExtensionsError -> ExtensionsResult
forall a b. a -> Either a b
Left ExtensionsError
err
        Right Map FilePath ParsedExtensions
cabalMap -> case FilePath -> Map FilePath ParsedExtensions -> Maybe ParsedExtensions
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
path Map FilePath ParsedExtensions
cabalMap of
            Maybe ParsedExtensions
Nothing -> ExtensionsResult -> IO ExtensionsResult
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExtensionsResult -> IO ExtensionsResult)
-> ExtensionsResult -> IO ExtensionsResult
forall a b. (a -> b) -> a -> b
$ ExtensionsError -> ExtensionsResult
forall a b. a -> Either a b
Left (ExtensionsError -> ExtensionsResult)
-> ExtensionsError -> ExtensionsResult
forall a b. (a -> b) -> a -> b
$ FilePath -> ExtensionsError
NotCabalModule FilePath
path
            Just ParsedExtensions
cabalExts -> do
                Either ModuleParseError ParsedExtensions
moduleRes <- FilePath -> IO (Either ModuleParseError ParsedExtensions)
parseFile FilePath
path
                ExtensionsResult -> IO ExtensionsResult
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExtensionsResult -> IO ExtensionsResult)
-> ExtensionsResult -> IO ExtensionsResult
forall a b. (a -> b) -> a -> b
$ ParsedExtensions
-> FilePath
-> Either ModuleParseError ParsedExtensions
-> ExtensionsResult
mergeCabalAndModule ParsedExtensions
cabalExts FilePath
path Either ModuleParseError ParsedExtensions
moduleRes

{- | By given path to @.cabal@ file and path to Haskell module of the
corresponding package, analyse and return extensions extensions for the
given module separately from .cabal file and from the module itself.
-}
getModuleAndCabalExtentionsBySource
    :: FilePath  -- ^ Maybe path to @.cabal@ file.
    -> FilePath  -- ^ Path to the module's source (needed for matching with cabal file).
    -> ByteString  -- ^ Source of a Haskell module file.
    -> IO (Either ExtensionsError CabalAndModuleExtensions)
getModuleAndCabalExtentionsBySource :: FilePath
-> FilePath
-> ByteString
-> IO (Either ExtensionsError CabalAndModuleExtensions)
getModuleAndCabalExtentionsBySource FilePath
cabalFile FilePath
path ByteString
source =
    FilePath
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
parseCabalHandleException FilePath
cabalFile IO (Either ExtensionsError (Map FilePath ParsedExtensions))
-> (Either ExtensionsError (Map FilePath ParsedExtensions)
    -> Either ExtensionsError CabalAndModuleExtensions)
-> IO (Either ExtensionsError CabalAndModuleExtensions)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
        Left ExtensionsError
cabalError -> ExtensionsError -> Either ExtensionsError CabalAndModuleExtensions
forall a b. a -> Either a b
Left ExtensionsError
cabalError
        Right Map FilePath ParsedExtensions
cabalMap -> case FilePath -> Map FilePath ParsedExtensions -> Maybe ParsedExtensions
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
path Map FilePath ParsedExtensions
cabalMap of
            Maybe ParsedExtensions
Nothing        -> ExtensionsError -> Either ExtensionsError CabalAndModuleExtensions
forall a b. a -> Either a b
Left (ExtensionsError
 -> Either ExtensionsError CabalAndModuleExtensions)
-> ExtensionsError
-> Either ExtensionsError CabalAndModuleExtensions
forall a b. (a -> b) -> a -> b
$ FilePath -> ExtensionsError
NotCabalModule FilePath
path
            Just ParsedExtensions
cabalExts -> FilePath
-> ParsedExtensions
-> Either ModuleParseError ParsedExtensions
-> Either ExtensionsError CabalAndModuleExtensions
getCabalAndModuleExts FilePath
path ParsedExtensions
cabalExts
                (FilePath -> ByteString -> Either ModuleParseError ParsedExtensions
parseSourceWithPath FilePath
path ByteString
source)

{- | By given path to @.cabal@ file and path to Haskell module of the
corresponding package, analyse and return combined set of extensions for the
given module.
-}
getModuleExtentionsBySource
    :: FilePath  -- ^ Maybe path to @.cabal@ file.
    -> FilePath  -- ^ Path to the module's source (needed for matching with cabal file).
    -> ByteString  -- ^ Source of a Haskell module file.
    -> IO ExtensionsResult
getModuleExtentionsBySource :: FilePath -> FilePath -> ByteString -> IO ExtensionsResult
getModuleExtentionsBySource FilePath
cabalFile FilePath
path ByteString
source =
    FilePath
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
parseCabalHandleException FilePath
cabalFile IO (Either ExtensionsError (Map FilePath ParsedExtensions))
-> (Either ExtensionsError (Map FilePath ParsedExtensions)
    -> ExtensionsResult)
-> IO ExtensionsResult
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
        Left ExtensionsError
cabalError -> ExtensionsError -> ExtensionsResult
forall a b. a -> Either a b
Left ExtensionsError
cabalError
        Right Map FilePath ParsedExtensions
cabalMap -> case FilePath -> Map FilePath ParsedExtensions -> Maybe ParsedExtensions
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
path Map FilePath ParsedExtensions
cabalMap of
            Maybe ParsedExtensions
Nothing        -> ExtensionsError -> ExtensionsResult
forall a b. a -> Either a b
Left (ExtensionsError -> ExtensionsResult)
-> ExtensionsError -> ExtensionsResult
forall a b. (a -> b) -> a -> b
$ FilePath -> ExtensionsError
NotCabalModule FilePath
path
            Just ParsedExtensions
cabalExts -> ParsedExtensions
-> FilePath
-> Either ModuleParseError ParsedExtensions
-> ExtensionsResult
mergeCabalAndModule ParsedExtensions
cabalExts FilePath
path
                (FilePath -> ByteString -> Either ModuleParseError ParsedExtensions
parseSourceWithPath FilePath
path ByteString
source)

----------------------------------------------------------------------------
-- Internal helpers
----------------------------------------------------------------------------

mergeCabalAndModule
    :: ParsedExtensions
    -> FilePath
    -> Either ModuleParseError ParsedExtensions
    -> ExtensionsResult
mergeCabalAndModule :: ParsedExtensions
-> FilePath
-> Either ModuleParseError ParsedExtensions
-> ExtensionsResult
mergeCabalAndModule ParsedExtensions
cabalExts FilePath
path Either ModuleParseError ParsedExtensions
moduleRes = case Either ModuleParseError ParsedExtensions
moduleRes of
    Right ParsedExtensions
moduleExts -> ParsedExtensions -> ParsedExtensions -> ExtensionsResult
mergeAnyExtensions ParsedExtensions
cabalExts ParsedExtensions
moduleExts
    Left ModuleParseError
parseErr    -> ExtensionsError -> ExtensionsResult
forall a b. a -> Either a b
Left (ExtensionsError -> ExtensionsResult)
-> ExtensionsError -> ExtensionsResult
forall a b. (a -> b) -> a -> b
$ FilePath -> ModuleParseError -> ExtensionsError
ModuleParseError FilePath
path ModuleParseError
parseErr

-- | 'parseCabalFileExtensions' with 'handleCabalException'.
parseCabalHandleException
    :: FilePath
    -> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
parseCabalHandleException :: FilePath
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
parseCabalHandleException FilePath
cabalFile = (Map FilePath ParsedExtensions
-> Either ExtensionsError (Map FilePath ParsedExtensions)
forall a b. b -> Either a b
Right (Map FilePath ParsedExtensions
 -> Either ExtensionsError (Map FilePath ParsedExtensions))
-> IO (Map FilePath ParsedExtensions)
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> IO (Map FilePath ParsedExtensions)
parseCabalFileExtensions FilePath
cabalFile)
    IO (Either ExtensionsError (Map FilePath ParsedExtensions))
-> (CabalException
    -> IO (Either ExtensionsError (Map FilePath ParsedExtensions)))
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` CabalException
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
handleCabalException

-- | Handle 'CabalException' and return corresponding 'CabalError'.
handleCabalException
    :: CabalException
    -> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
handleCabalException :: CabalException
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
handleCabalException = Either ExtensionsError (Map FilePath ParsedExtensions)
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ExtensionsError (Map FilePath ParsedExtensions)
 -> IO (Either ExtensionsError (Map FilePath ParsedExtensions)))
-> (CabalException
    -> Either ExtensionsError (Map FilePath ParsedExtensions))
-> CabalException
-> IO (Either ExtensionsError (Map FilePath ParsedExtensions))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExtensionsError
-> Either ExtensionsError (Map FilePath ParsedExtensions)
forall a b. a -> Either a b
Left (ExtensionsError
 -> Either ExtensionsError (Map FilePath ParsedExtensions))
-> (CabalException -> ExtensionsError)
-> CabalException
-> Either ExtensionsError (Map FilePath ParsedExtensions)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CabalException -> ExtensionsError
CabalError

getCabalAndModuleExts
    :: FilePath
    -> ParsedExtensions
    -> Either ModuleParseError ParsedExtensions
    -> Either ExtensionsError CabalAndModuleExtensions
getCabalAndModuleExts :: FilePath
-> ParsedExtensions
-> Either ModuleParseError ParsedExtensions
-> Either ExtensionsError CabalAndModuleExtensions
getCabalAndModuleExts FilePath
path ParsedExtensions
cabalExts Either ModuleParseError ParsedExtensions
moduleRes = case Either ModuleParseError ParsedExtensions
moduleRes of
    Left ModuleParseError
err -> ExtensionsError -> Either ExtensionsError CabalAndModuleExtensions
forall a b. a -> Either a b
Left (ExtensionsError
 -> Either ExtensionsError CabalAndModuleExtensions)
-> ExtensionsError
-> Either ExtensionsError CabalAndModuleExtensions
forall a b. (a -> b) -> a -> b
$ FilePath -> ModuleParseError -> ExtensionsError
ModuleParseError FilePath
path ModuleParseError
err
    Right ParsedExtensions
moduleExts -> CabalAndModuleExtensions
-> Either ExtensionsError CabalAndModuleExtensions
forall a b. b -> Either a b
Right (CabalAndModuleExtensions
 -> Either ExtensionsError CabalAndModuleExtensions)
-> CabalAndModuleExtensions
-> Either ExtensionsError CabalAndModuleExtensions
forall a b. (a -> b) -> a -> b
$ CabalAndModuleExtensions
        { cabalExtensions :: ParsedExtensions
cabalExtensions  = ParsedExtensions
cabalExts
        , moduleExtensions :: ParsedExtensions
moduleExtensions = ParsedExtensions
moduleExts
        }