{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
module CabalFmt.Refactoring (
Refactoring,
Refactoring',
refactoringExpandExposedModules,
) where
import Data.List (intercalate)
import Data.Maybe (catMaybes)
import System.FilePath (dropExtension, splitDirectories)
import qualified Distribution.Fields as C
import qualified Distribution.ModuleName as C
import qualified Distribution.Simple.Utils as C
import CabalFmt.Comments
import CabalFmt.Monad
import CabalFmt.Pragma
type C = (Comments, [Pragma])
type Refactoring = forall m. MonadCabalFmt m => Refactoring' m
type Refactoring' m = [C.Field C] -> m [C.Field C]
type RefactoringOfField = forall m. MonadCabalFmt m => RefactoringOfField' m
type RefactoringOfField' m = C.Name C -> [C.FieldLine C] -> m (C.Name C, [C.FieldLine C])
refactoringExpandExposedModules :: Refactoring
refactoringExpandExposedModules = traverseFields refact where
refact :: RefactoringOfField
refact name@(C.Name (_, pragmas) n) fls
| n == "exposed-modules" || n == "other-modules" = do
dirs <- parse pragmas
files <- traverseOf (traverse . _1) getFiles dirs
let newModules :: [C.FieldLine C]
newModules = catMaybes
[ return $ C.FieldLine mempty $ C.toUTF8BS $ intercalate "." parts
| (files', mns) <- files
, file <- files'
, let parts = splitDirectories $ dropExtension file
, all C.validModuleComponent parts
, let mn = C.fromComponents parts
, mn `notElem` mns
]
pure (name, newModules ++ fls)
| otherwise = pure (name, fls)
parse :: MonadCabalFmt m => [Pragma] -> m [(FilePath, [C.ModuleName])]
parse = fmap mconcat . traverse go where
go (PragmaExpandModules fp mns) = return [ (fp, mns) ]
go p = do
displayWarning $ "Skipped pragma " ++ show p
return []
traverseOf
:: Applicative f
=> ((a -> f b) -> s -> f t)
-> (a -> f b) -> s -> f t
traverseOf = id
_1 :: Functor f => (a -> f b) -> (a, c) -> f (b, c)
_1 f (a, c) = (\b -> (b, c)) <$> f a
traverseFields
:: Applicative f
=> RefactoringOfField' f
-> [C.Field C] -> f [C.Field C]
traverseFields f = goMany where
goMany = traverse go
go (C.Field name fls) = uncurry C.Field <$> f name fls
go (C.Section name args fs) = C.Section name args <$> goMany fs