-- | Build-time checks that content is consistent across files
module MathiasSM.Validate (validateNavEntries) where

import Control.Monad (unless)
import Hakyll (Rules, getAllMetadata, preprocess, toFilePath)
import MathiasSM.Config (SiteConfig, pagesPattern)
import MathiasSM.Content (parseNavEntry)

{- | Fails the build, once, listing every page whose menu entry (`nav:`) is invalid

Without this each page would report the same problem while rendering the menu.
-}
validateNavEntries :: SiteConfig -> Rules ()
validateNavEntries :: SiteConfig -> Rules ()
validateNavEntries SiteConfig
cfg = do
    pages <- Pattern -> Rules [(Identifier, Metadata)]
forall (m :: * -> *).
MonadMetadata m =>
Pattern -> m [(Identifier, Metadata)]
getAllMetadata (Pattern -> Rules [(Identifier, Metadata)])
-> Pattern -> Rules [(Identifier, Metadata)]
forall a b. (a -> b) -> a -> b
$ SiteConfig -> [Char] -> Pattern
pagesPattern SiteConfig
cfg [Char]
"*"
    let problems = [Identifier -> [Char]
toFilePath Identifier
page [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
": " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
problem | (Identifier
page, Metadata
metadata) <- [(Identifier, Metadata)]
pages, Left [[Char]]
found <- [Metadata -> Either [[Char]] (Maybe NavEntry)
parseNavEntry Metadata
metadata], [Char]
problem <- [[Char]]
found]
    unless (null problems)
        $ preprocess
        $ ioError
        $ userError
        $ "Invalid menu entries:\n" ++ unlines (map ("  " ++) problems)