{-# LANGUAGE CPP #-}
module Text.Microstache.Compile
( compileMustacheDir
, getMustacheFilesInDir
, compileMustacheFile
, compileMustacheText )
where
import Control.Exception (throwIO)
import Control.Monad (filterM, foldM)
import Data.Text.Lazy (Text)
import System.Directory
(doesFileExist, getCurrentDirectory, getDirectoryContents)
import Text.Parsec (ParseError)
import qualified Data.Map as Map
import qualified Data.Text as T
import qualified Data.Text.Lazy.IO as LT
import qualified System.FilePath as F
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Text.Microstache.Parser
import Text.Microstache.Type
compileMustacheDir
:: PName
-> FilePath
-> IO Template
compileMustacheDir :: PName -> FilePath -> IO Template
compileMustacheDir PName
pname FilePath
path =
FilePath -> IO [FilePath]
getMustacheFilesInDir FilePath
path forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Template -> Template
selectKey forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Template -> FilePath -> IO Template
f (PName -> Map PName [Node] -> Template
Template forall a. HasCallStack => a
undefined forall k a. Map k a
Map.empty)
where
selectKey :: Template -> Template
selectKey Template
t = Template
t { templateActual :: PName
templateActual = PName
pname }
f :: Template -> FilePath -> IO Template
f (Template PName
_ Map PName [Node]
old) FilePath
fp = do
Template PName
_ Map PName [Node]
new <- FilePath -> IO Template
compileMustacheFile FilePath
fp
forall (m :: * -> *) a. Monad m => a -> m a
return (PName -> Map PName [Node] -> Template
Template forall a. HasCallStack => a
undefined (forall k a. Ord k => Map k a -> Map k a -> Map k a
Map.union Map PName [Node]
new Map PName [Node]
old))
getMustacheFilesInDir
:: FilePath
-> IO [FilePath]
getMustacheFilesInDir :: FilePath -> IO [FilePath]
getMustacheFilesInDir FilePath
path =
FilePath -> IO [FilePath]
getDirectoryContents FilePath
path forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM FilePath -> IO Bool
isMustacheFile forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (FilePath -> FilePath -> FilePath
F.combine FilePath
path) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM FilePath -> IO FilePath
makeAbsolute'
compileMustacheFile
:: FilePath
-> IO Template
compileMustacheFile :: FilePath -> IO Template
compileMustacheFile FilePath
path =
FilePath -> IO Text
LT.readFile FilePath
path forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either ParseError Template -> IO Template
withException forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either ParseError Template
compile
where
pname :: PName
pname = FilePath -> PName
pathToPName FilePath
path
compile :: Text -> Either ParseError Template
compile = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (PName -> Map PName [Node] -> Template
Template PName
pname forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. k -> a -> Map k a
Map.singleton PName
pname) forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text -> Either ParseError [Node]
parseMustache FilePath
path
compileMustacheText
:: PName
-> Text
-> Either ParseError Template
compileMustacheText :: PName -> Text -> Either ParseError Template
compileMustacheText PName
pname Text
txt =
PName -> Map PName [Node] -> Template
Template PName
pname forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. k -> a -> Map k a
Map.singleton PName
pname forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> Text -> Either ParseError [Node]
parseMustache FilePath
"" Text
txt
isMustacheFile :: FilePath -> IO Bool
isMustacheFile :: FilePath -> IO Bool
isMustacheFile FilePath
path = do
Bool
exists <- FilePath -> IO Bool
doesFileExist FilePath
path
let rightExtension :: Bool
rightExtension = FilePath -> FilePath
F.takeExtension FilePath
path forall a. Eq a => a -> a -> Bool
== FilePath
".mustache"
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
exists Bool -> Bool -> Bool
&& Bool
rightExtension)
pathToPName :: FilePath -> PName
pathToPName :: FilePath -> PName
pathToPName = Text -> PName
PName forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
T.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
F.takeBaseName
withException
:: Either ParseError Template
-> IO Template
withException :: Either ParseError Template -> IO Template
withException = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall e a. Exception e => e -> IO a
throwIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseError -> MustacheException
MustacheParserException) forall (m :: * -> *) a. Monad m => a -> m a
return
makeAbsolute' :: FilePath -> IO FilePath
makeAbsolute' :: FilePath -> IO FilePath
makeAbsolute' FilePath
path0 =
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (FilePath -> FilePath -> FilePath
matchTrailingSeparator FilePath
path0 forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
F.normalise) (FilePath -> IO FilePath
prependCurrentDirectory FilePath
path0)
where
prependCurrentDirectory :: FilePath -> IO FilePath
prependCurrentDirectory :: FilePath -> IO FilePath
prependCurrentDirectory FilePath
path =
if FilePath -> Bool
F.isRelative FilePath
path
then (FilePath -> FilePath -> FilePath
F.</> FilePath
path) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO FilePath
getCurrentDirectory
else forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
path
matchTrailingSeparator :: FilePath -> FilePath -> FilePath
matchTrailingSeparator :: FilePath -> FilePath -> FilePath
matchTrailingSeparator FilePath
path
| FilePath -> Bool
F.hasTrailingPathSeparator FilePath
path = FilePath -> FilePath
F.addTrailingPathSeparator
| Bool
otherwise = FilePath -> FilePath
F.dropTrailingPathSeparator