{-# LANGUAGE CPP #-}
{-# LANGUAGE Rank2Types #-}
module Hakyll.Core.Routes
( UsedMetadata
, Routes
, runRoutes
, idRoute
, setExtension
, matchRoute
, customRoute
, constRoute
, gsubRoute
, metadataRoute
, composeRoutes
) where
#if MIN_VERSION_base(4,9,0)
import Data.Semigroup (Semigroup (..))
#endif
import System.FilePath (replaceExtension, normalise)
import Hakyll.Core.Identifier
import Hakyll.Core.Identifier.Pattern
import Hakyll.Core.Metadata
import Hakyll.Core.Provider
import Hakyll.Core.Util.String
type UsedMetadata = Bool
data RoutesRead = RoutesRead
{ RoutesRead -> Provider
routesProvider :: Provider
, RoutesRead -> Identifier
routesUnderlying :: Identifier
}
newtype Routes = Routes
{ Routes
-> RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
unRoutes :: RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
}
#if MIN_VERSION_base(4,9,0)
instance Semigroup Routes where
<> :: Routes -> Routes -> Routes
(<>) (Routes RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
f) (Routes RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
g) = (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
Routes ((RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes)
-> (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
forall a b. (a -> b) -> a -> b
$ \RoutesRead
p Identifier
id' -> do
(Maybe FilePath
mfp, UsedMetadata
um) <- RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
f RoutesRead
p Identifier
id'
case Maybe FilePath
mfp of
Maybe FilePath
Nothing -> RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
g RoutesRead
p Identifier
id'
Just FilePath
_ -> (Maybe FilePath, UsedMetadata) -> IO (Maybe FilePath, UsedMetadata)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe FilePath
mfp, UsedMetadata
um)
instance Monoid Routes where
mempty :: Routes
mempty = (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
Routes ((RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes)
-> (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
forall a b. (a -> b) -> a -> b
$ \RoutesRead
_ Identifier
_ -> (Maybe FilePath, UsedMetadata) -> IO (Maybe FilePath, UsedMetadata)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe FilePath
forall a. Maybe a
Nothing, UsedMetadata
False)
mappend :: Routes -> Routes -> Routes
mappend = Routes -> Routes -> Routes
forall a. Semigroup a => a -> a -> a
(<>)
#else
instance Monoid Routes where
mempty = Routes $ \_ _ -> return (Nothing, False)
mappend (Routes f) (Routes g) = Routes $ \p id' -> do
(mfp, um) <- f p id'
case mfp of
Nothing -> g p id'
Just _ -> return (mfp, um)
#endif
runRoutes :: Routes -> Provider -> Identifier
-> IO (Maybe FilePath, UsedMetadata)
runRoutes :: Routes
-> Provider -> Identifier -> IO (Maybe FilePath, UsedMetadata)
runRoutes Routes
routes Provider
provider Identifier
identifier =
Routes
-> RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
unRoutes Routes
routes (Provider -> Identifier -> RoutesRead
RoutesRead Provider
provider Identifier
identifier) Identifier
identifier
idRoute :: Routes
idRoute :: Routes
idRoute = (Identifier -> FilePath) -> Routes
customRoute Identifier -> FilePath
toFilePath
setExtension :: String -> Routes
setExtension :: FilePath -> Routes
setExtension FilePath
extension = (Identifier -> FilePath) -> Routes
customRoute ((Identifier -> FilePath) -> Routes)
-> (Identifier -> FilePath) -> Routes
forall a b. (a -> b) -> a -> b
$
(FilePath -> FilePath -> FilePath
`replaceExtension` FilePath
extension) (FilePath -> FilePath)
-> (Identifier -> FilePath) -> Identifier -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> FilePath
toFilePath
matchRoute :: Pattern -> Routes -> Routes
matchRoute :: Pattern -> Routes -> Routes
matchRoute Pattern
pattern (Routes RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
route) = (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
Routes ((RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes)
-> (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
forall a b. (a -> b) -> a -> b
$ \RoutesRead
p Identifier
id' ->
if Pattern -> Identifier -> UsedMetadata
matches Pattern
pattern Identifier
id' then RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
route RoutesRead
p Identifier
id' else (Maybe FilePath, UsedMetadata) -> IO (Maybe FilePath, UsedMetadata)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe FilePath
forall a. Maybe a
Nothing, UsedMetadata
False)
customRoute :: (Identifier -> FilePath) -> Routes
customRoute :: (Identifier -> FilePath) -> Routes
customRoute Identifier -> FilePath
f = (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
Routes ((RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes)
-> (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
forall a b. (a -> b) -> a -> b
$ (Identifier -> IO (Maybe FilePath, UsedMetadata))
-> RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
forall a b. a -> b -> a
const ((Identifier -> IO (Maybe FilePath, UsedMetadata))
-> RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> (Identifier -> IO (Maybe FilePath, UsedMetadata))
-> RoutesRead
-> Identifier
-> IO (Maybe FilePath, UsedMetadata)
forall a b. (a -> b) -> a -> b
$ \Identifier
id' -> (Maybe FilePath, UsedMetadata) -> IO (Maybe FilePath, UsedMetadata)
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just (Identifier -> FilePath
f Identifier
id'), UsedMetadata
False)
constRoute :: FilePath -> Routes
constRoute :: FilePath -> Routes
constRoute = (Identifier -> FilePath) -> Routes
customRoute ((Identifier -> FilePath) -> Routes)
-> (FilePath -> Identifier -> FilePath) -> FilePath -> Routes
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Identifier -> FilePath
forall a b. a -> b -> a
const
gsubRoute :: String
-> (String -> String)
-> Routes
gsubRoute :: FilePath -> (FilePath -> FilePath) -> Routes
gsubRoute FilePath
pattern FilePath -> FilePath
replacement = (Identifier -> FilePath) -> Routes
customRoute ((Identifier -> FilePath) -> Routes)
-> (Identifier -> FilePath) -> Routes
forall a b. (a -> b) -> a -> b
$
FilePath -> FilePath
normalise (FilePath -> FilePath)
-> (Identifier -> FilePath) -> Identifier -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> (FilePath -> FilePath) -> FilePath -> FilePath
replaceAll FilePath
pattern (FilePath -> FilePath
replacement (FilePath -> FilePath)
-> (FilePath -> FilePath) -> FilePath -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
removeWinPathSeparator) (FilePath -> FilePath)
-> (Identifier -> FilePath) -> Identifier -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath
removeWinPathSeparator (FilePath -> FilePath)
-> (Identifier -> FilePath) -> Identifier -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> FilePath
toFilePath
where
metadataRoute :: (Metadata -> Routes) -> Routes
metadataRoute :: (Metadata -> Routes) -> Routes
metadataRoute Metadata -> Routes
f = (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
Routes ((RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes)
-> (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
forall a b. (a -> b) -> a -> b
$ \RoutesRead
r Identifier
i -> do
Metadata
metadata <- Provider -> Identifier -> IO Metadata
resourceMetadata (RoutesRead -> Provider
routesProvider RoutesRead
r) (RoutesRead -> Identifier
routesUnderlying RoutesRead
r)
Routes
-> RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
unRoutes (Metadata -> Routes
f Metadata
metadata) RoutesRead
r Identifier
i
composeRoutes :: Routes
-> Routes
-> Routes
composeRoutes :: Routes -> Routes -> Routes
composeRoutes (Routes RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
f) (Routes RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
g) = (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
Routes ((RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes)
-> (RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata))
-> Routes
forall a b. (a -> b) -> a -> b
$ \RoutesRead
p Identifier
i -> do
(Maybe FilePath
mfp, UsedMetadata
um) <- RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
f RoutesRead
p Identifier
i
case Maybe FilePath
mfp of
Maybe FilePath
Nothing -> (Maybe FilePath, UsedMetadata) -> IO (Maybe FilePath, UsedMetadata)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe FilePath
forall a. Maybe a
Nothing, UsedMetadata
um)
Just FilePath
fp -> do
(Maybe FilePath
mfp', UsedMetadata
um') <- RoutesRead -> Identifier -> IO (Maybe FilePath, UsedMetadata)
g RoutesRead
p (FilePath -> Identifier
fromFilePath FilePath
fp)
(Maybe FilePath, UsedMetadata) -> IO (Maybe FilePath, UsedMetadata)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe FilePath
mfp', UsedMetadata
um UsedMetadata -> UsedMetadata -> UsedMetadata
|| UsedMetadata
um')