shakebook-0.4.0.0: test/Spec.hs
{-# LANGUAGE TemplateHaskell #-}
import Control.Comonad.Cofree
import Control.Comonad.Store
import Control.Comonad.Store.Zipper
import Control.Comonad.Zipper.Extra
import Data.Aeson
import Data.Aeson.With
import Data.List.Split
import Data.Text.Time
import Development.Shake.Plus
import Path
import RIO
import RIO.Partial
import qualified RIO.HashMap as HM
import RIO.List
import RIO.List.Partial
import qualified RIO.Text as T
import Shakebook.Data
import Shakebook.Defaults
import Shakebook.Mustache
import Shakebook.Conventions
import Test.Tasty
import Test.Tasty.Golden
import Text.Pandoc.Highlighting
import Within
sourceFolder :: Path Rel Dir
sourceFolder = $(mkRelDir "test/site")
outputFolder :: Path Rel Dir
outputFolder = $(mkRelDir "test/public")
--baseUrl :: Text
--baseUrl = "http://blanky.test"
siteTitle :: Text
siteTitle = "Blanky Site"
tableOfContents :: Cofree [] (Path Rel File)
tableOfContents = $(mkRelFile "docs/index.md") :< [
$(mkRelFile "docs/1/index.md") :< []
, $(mkRelFile "docs/2/index.md") :< [
$(mkRelFile "docs/2/champ.md") :< []
]
]
numRecentPosts :: Int
numRecentPosts = 3
numPageNeighbours :: Int
numPageNeighbours = 1
postsPerPage :: Int
postsPerPage = 5
mySocial :: [Value]
mySocial = uncurry genLinkData <$> [("twitter", "http://twitter.com/blanky-site-nowhere")
,("youtube", "http://youtube.com/blanky-site-nowhere")
,("gitlab", "http://gitlab.com/blanky-site-nowhere")]
rules :: HasLogFunc r => ShakePlus r ()
rules = do
readMDC <- newCache $ loadMarkdownAsJSON defaultMarkdownReaderOptions defaultHtml5WriterOptions
postsC <- newCache $ \w -> do
xs <- batchLoadWithin' w readMDC
return $ defaultEnrichPost <$> xs
sortedPosts <- newCache $ \fp -> do
allPosts <- postsC fp
return $ sortOn (Down . viewPostTime . snd) $ HM.toList allPosts
getRecentPosts <- newCache $ \fp -> do
xs <- sortedPosts fp
return $ take numRecentPosts (snd <$> xs)
getBlogNavbar <- newCache $ \fp -> do
allPosts <- postsC fp
return $ genBlogNavbarData "Blog" "/posts/"
(T.pack . defaultPrettyMonthFormat)
(defaultMonthUrlFragment) (HM.elems allPosts)
let myPosts = ["posts/*.md"] `within` sourceFolder
myBuildPage tmpl v out = do
rs <- getRecentPosts myPosts
let v' = withHighlighting pygments
. withSocialLinks mySocial
. withSiteTitle siteTitle
. withRecentPosts rs $ v
buildPageActionWithin (tmpl `within` sourceFolder) v' out
("index.html" `within` outputFolder) %^> \out -> do
src <- blinkAndMapM sourceFolder withMarkdownExtension $ out
v <- readMDC src
myBuildPage $(mkRelFile "templates/index.html") v out
("posts/*.html" `within` outputFolder) %^> \out -> do
src <- blinkAndMapM sourceFolder withMarkdownExtension $ out
xs <- sortedPosts myPosts
let k = elemIndex src (fst <$> xs)
let z = fromJust $ liftA2 seek k $ zipper (snd <$> xs)
n <- getBlogNavbar myPosts
let v' = withJSON n $ (extract z)
myBuildPage $(mkRelFile "templates/post.html") v' out
toc' <- mapM (mapM withHtmlExtension) $ fmap (`within` outputFolder) tableOfContents
void . sequence . flip extend toc' $ \xs -> (fmap toFilePath $ extract xs) %^> \out -> do
let getDoc = readMDC <=< blinkAndMapM sourceFolder withMarkdownExtension
ys <- mapM getDoc toc'
zs <- mapM getDoc $ (immediateShoots xs)
v <- getDoc $ out
let v' = withJSON (genTocNavbarData ys) . withSubsections zs $ v
myBuildPage $(mkRelFile "templates/docs.html") v' out
("posts/index.html" `within` outputFolder) %^>
copyFileChangedWithin ($(mkRelFile "posts/pages/1/index.html") `within` outputFolder)
("posts/pages/*/index.html" `within` outputFolder) %^> \out -> do
xs <- sortedPosts myPosts
let n = (+ (-1)) . read . (!! 2) . splitOn "/" . toFilePath . extract $ out
p <- seek n <$> genIndexPageData (snd <$> xs) "Posts" ("/posts/pages/" <>) postsPerPage
k <- getBlogNavbar myPosts
let v = withJSON k $ extract $ extendPageNeighbours numPageNeighbours p
myBuildPage $(mkRelFile "templates/post-list.html") v out
("posts/tags/*/index.html" `within` outputFolder) %^> \out -> do
let t = (!! 2) . splitOn "/" . toFilePath . extract $ out
i <- parseRelFile $ "posts/tags/" <> t <> "/pages/1/index.html"
copyFileChangedWithin (i `within` outputFolder) out
("posts/tags/*/pages/*/index.html" `within` outputFolder) %^> \out -> do
let t = T.pack . (!! 2) . splitOn "/" . toFilePath . extract $ out
xs <- filter (elem t . viewTags . snd) <$> sortedPosts myPosts
let n = (+ (-1)) . read . (!! 4) . splitOn "/" . toFilePath . extract $ out
p <- seek n <$> genIndexPageData (snd <$> xs) ("Posts tagged " <> t) (("/posts/tags/" <> t <> "/pages/") <>) postsPerPage
k <- getBlogNavbar myPosts
let v = withJSON k $ extract $ extendPageNeighbours numPageNeighbours p
myBuildPage $(mkRelFile "templates/post-list.html") v out
("posts/months/*/index.html" `within` outputFolder) %^> \out -> do
let t = (!! 2) . splitOn "/" . toFilePath . extract $ out
i <- parseRelFile $ "posts/months/" <> t <> "/pages/1/index.html"
copyFileChangedWithin (i `within` outputFolder) out
("posts/months/*/pages/*/index.html" `within` outputFolder) %^> \out -> do
let t = parseISODateTime . T.pack . (!! 2) . splitOn "/" . toFilePath . extract $ out
xs <- filter (sameMonth t . viewPostTime . snd) <$> sortedPosts myPosts
let n = (+ (-1)) . read . (!! 4) . splitOn "/" . toFilePath . extract $ out
p <- seek n <$> genIndexPageData (snd <$> xs)
(("Posts from " <>) . T.pack . defaultPrettyMonthFormat $ t)
(("/posts/months/" <> T.pack (defaultMonthUrlFormat t) <> "/pages/") <>) postsPerPage
k <- getBlogNavbar myPosts
let v = withJSON k $ extract $ extendPageNeighbours numPageNeighbours p
myBuildPage $(mkRelFile "templates/post-list.html") v out
phony "index" $
needIn outputFolder [$(mkRelFile "index.html")]
phony "post-index" $ do
xs <- sortedPosts myPosts
ps <- paginate' postsPerPage xs
fs <- defaultPagePaths [1..size ps]
needIn (outputFolder </> $(mkRelDir "posts")) ($(mkRelFile "index.html") : fs)
phony "by-tag-index" $ do
xs <- sortedPosts myPosts
forM_ (viewAllPostTags (snd <$> xs)) $ \t -> do
u <- parseRelDir $ T.unpack t
let xs' = filter (elem t . viewTags . snd) xs
ps <- paginate' postsPerPage xs'
fs <- defaultPagePaths [1..size ps]
let tagFolder = outputFolder </> $(mkRelDir "posts/tags") </> u
needIn tagFolder ($(mkRelFile "index.html") : fs)
phony "by-month-index" $ do
xs <- sortedPosts myPosts
forM_ (viewAllPostTimes (snd <$> xs)) $ \t -> do
u <- parseRelDir $ defaultMonthUrlFormat t
let monthFolder = outputFolder </> $(mkRelDir "posts/months") </> u
let xs' = filter (sameMonth t . viewPostTime . snd) xs
ps <- paginate' postsPerPage xs'
fs <- defaultPagePaths [1..size ps]
needIn monthFolder ($(mkRelFile "index.html") : fs)
phony "docs" $
mapM withHtmlExtension tableOfContents >>= needIn outputFolder
phony "posts" $
getDirectoryFilesWithin' (["posts/*.md"] `within` sourceFolder) >>=
mapM (blinkAndMapM outputFolder withHtmlExtension) >>=
needWithin'
phony "clean" $ do
logInfo $ "Cleaning files in " <> display (PathDisplay outputFolder)
removeFilesAfter outputFolder ["//*"]
tests :: [FilePath] -> TestTree
tests xs = testGroup "Rendering Tests" $
map ( \x -> goldenVsFile x x
(replace "golden" "public" x)
(return ())) xs
where replace from to' = intercalate to' . splitOn from
main :: IO ()
main = do
xs <- findByExtension [".html"] "test/golden"
logOptions' <- logOptionsHandle stdout True
(lf, dlf) <- newLogFunc (setLogMinLevel LevelInfo logOptions')
shake shakeOptions $ want ["clean"] >> runShakePlus lf rules
shake shakeOptions $ want ["index", "docs", "posts", "post-index", "by-tag-index", "by-month-index"] >> runShakePlus lf rules
defaultMain $ tests xs
dlf