#!/usr/bin/env runhaskell {-# LANGUAGE OverloadedStrings #-} import Control.Monad import Data.Aeson import qualified Data.ByteString.Lazy as BS import Data.Default import qualified Data.HashMap.Strict as HM import Data.Microformats2.Parser import qualified Data.Vector as V import Network.URI import System.Directory import System.Environment parse = parseMf2 def . documentRoot . parseLBS isHentry :: Value -> Bool isHentry (Object o) = case HM.lookup "type" o of Just (Array types) -> V.elem (String "h-entry") types _ -> False isHentry _ = False getHentries :: Value -> [Value] getHentries v = case v of Object o -> if isHentry (Object o) then [Object o] else HM.foldl' acc [] o Array a -> V.foldl' acc [] a _ -> [] where acc result val = result ++ getHentries val hasOneHentry :: Value -> Bool hasOneHentry = (== 1) . length . getHentries stringHasOneHentry = hasOneHentry . parse blogFiles :: IO [FilePath] blogFiles = do dir <- blogDir contents <- getDirectoryContents dir return (filter (`notElem` [".", "..", "index.html"]) contents) blogDir :: IO FilePath blogDir = fmap (++ "/blog") (getEnv "rendered") blogsWithoutEntry :: IO [FilePath] blogsWithoutEntry = blogFiles >>= filterM missing where missing f = do dir <- blogDir keep <$> BS.readFile (dir ++ "/" ++ f) keep = not . hasOneHentry . parse main = do without <- blogsWithoutEntry if null without then return () else error ("Expected one h-entry in " ++ show without)