{-# LANGUAGE CPP #-}
module Text.Mustache.Compile
( compileMustacheDir
, compileMustacheDir'
, getMustacheFilesInDir
, getMustacheFilesInDir'
, isMustacheFile
, compileMustacheFile
, compileMustacheText )
where
import Control.Exception
import Control.Monad.Except
import Data.Text (Text)
import Data.Void
import System.Directory
import Text.Megaparsec
import Text.Mustache.Parser
import Text.Mustache.Type
import qualified Data.Map as M
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified System.FilePath as F
compileMustacheDir :: MonadIO m
=> PName
-> FilePath
-> m Template
compileMustacheDir = compileMustacheDir' isMustacheFile
compileMustacheDir' :: MonadIO m
=> (FilePath -> Bool)
-> PName
-> FilePath
-> m Template
compileMustacheDir' predicate pname path =
getMustacheFilesInDir' predicate path >>=
fmap selectKey . foldM f (Template undefined M.empty)
where
selectKey t = t { templateActual = pname }
f (Template _ old) fp = do
Template _ new <- compileMustacheFile fp
return (Template undefined (M.union new old))
getMustacheFilesInDir :: MonadIO m
=> FilePath
-> m [FilePath]
getMustacheFilesInDir = getMustacheFilesInDir' isMustacheFile
getMustacheFilesInDir' :: MonadIO m
=> (FilePath -> Bool)
-> FilePath
-> m [FilePath]
getMustacheFilesInDir' predicate path = liftIO $
getDirectoryContents path >>=
filterM f . fmap (F.combine path) >>=
mapM makeAbsolute
where
f p = (&& predicate p) <$> doesFileExist p
isMustacheFile :: FilePath -> Bool
isMustacheFile path = F.takeExtension path == ".mustache"
compileMustacheFile :: MonadIO m
=> FilePath
-> m Template
compileMustacheFile path = liftIO $ do
input <- T.readFile path
withException (compile input)
where
pname = pathToPName path
compile = fmap (Template pname . M.singleton pname) . parseMustache path
compileMustacheText
:: PName
-> Text
-> Either (ParseErrorBundle Text Void) Template
compileMustacheText pname txt =
Template pname . M.singleton pname <$> parseMustache "" txt
pathToPName :: FilePath -> PName
pathToPName = PName . T.pack . F.takeBaseName
withException
:: Either (ParseErrorBundle Text Void) Template
-> IO Template
withException = either (throwIO . MustacheParserException) return