blog/blog-meta/lib/YAML.hs

55 lines
1.5 KiB
Haskell

{-# OPTIONS_GHC -Wno-orphans #-}
module YAML (module YAML, module Data.YAML, untagged) where
import Data.ByteString (ByteString)
import Data.ByteString.Char8 qualified as BS8
import Data.ByteString.Lazy qualified as LazyBS
import Data.Text (Text)
import Data.Text qualified as Text
import Data.YAML
import Data.YAML.Event (untagged)
import Misc
import System.IO qualified as IO
str' :: String -> Node ()
str' = str . Text.pack
str :: Text -> Node ()
str = Scalar () . SStr
obj :: Mapping () -> Node ()
obj = Mapping () untagged
(##=) :: (ToYAML b) => Text -> b -> (Node (), Node ())
(##=) = (#=)
(#=) :: (ToYAML a, ToYAML b) => a -> b -> (Node (), Node ())
k #= v = (toYAML k, toYAML v)
list :: ToYAML a => [a] -> Node ()
list = Sequence () untagged . map toYAML
-- | read a chunk from the beginning of the file between a
-- @---@ and a @...@. throw an exception if there isn't one
readHeader :: FilePath -> IO (Node Pos)
readHeader file = IO.withFile file IO.ReadMode \h -> do
ln <- BS8.hGetLine h
if (ln /= "---") then
fail $ file <> ": no header"
else
unwrap file . decode1 =<< linesUntil "..." h
-- | read all the lines from a handle until the given terminator. return the
-- lines read, excluding the terminator
linesUntil :: ByteString -> IO.Handle -> IO LazyBS.ByteString
linesUntil end h = go [] where
go acc = do
l <- BS8.hGetLine h
if l == end then
return $ LazyBS.fromChunks $ reverse acc
else
go ("\n" : l : acc)
instance FromYAML IsoDate where parseYAML = withStr "iso date" parseIsoDate