hakyll 4.16.6.0 → 4.16.7.0
raw patch · 10 files changed
+243/−39 lines, 10 filesdep +xml-conduitdep ~containersPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: xml-conduit
Dependency ranges changed: containers
API changes (from Hackage documentation)
+ Hakyll.Web.Feed: renderAtomNoValidate :: FeedConfiguration -> Context String -> [Item String] -> Compiler (Item String)
+ Hakyll.Web.Feed: renderAtomWithTemplatesNoValidate :: Template -> Template -> FeedConfiguration -> Context String -> [Item String] -> Compiler (Item String)
+ Hakyll.Web.Feed: renderRssNoValidate :: FeedConfiguration -> Context String -> [Item String] -> Compiler (Item String)
+ Hakyll.Web.Feed: renderRssWithTemplatesNoValidate :: Template -> Template -> FeedConfiguration -> Context String -> [Item String] -> Compiler (Item String)
+ Hakyll.Web.Feed: validateXMLFeed :: Item String -> Compiler (Item String)
+ Hakyll.Web.Pandoc.FileType: Typst :: FileType
- Hakyll.Core.Logger: flush :: Logger -> forall m. MonadIO m => m ()
+ Hakyll.Core.Logger: flush :: Logger -> forall (m :: Type -> Type). MonadIO m => m ()
- Hakyll.Core.Metadata: class Monad m => MonadMetadata m
+ Hakyll.Core.Metadata: class Monad m => MonadMetadata (m :: Type -> Type)
- Hakyll.Core.Store: get :: forall a. (Binary a, Typeable a) => Store -> [String] -> IO (Result a)
+ Hakyll.Core.Store: get :: (Binary a, Typeable a) => Store -> [String] -> IO (Result a)
Files
- CHANGELOG.md +8/−2
- hakyll.cabal +11/−9
- lib/Hakyll/Core/Util/String.hs +9/−13
- lib/Hakyll/Web/Feed.hs +112/−10
- lib/Hakyll/Web/Pandoc.hs +6/−0
- lib/Hakyll/Web/Pandoc/FileType.hs +11/−0
- tests/Hakyll/Core/Util/String/Tests.hs +14/−2
- tests/Hakyll/Web/Feed/Tests.hs +68/−0
- tests/TestSuite.hs +2/−0
- web/site.hs +2/−3
CHANGELOG.md view
@@ -4,10 +4,16 @@ # Releases +## Hakyll 4.16.7.0 (2025-08-29)++- Validate the output of XML-based feed functions such as `renderRss` by default (#1078).+- Bump `containers` upper bound to include 0.8.+- Add support for Typst (#1067).+ ## Hakyll 4.16.6.0 (2025-02-18) -- Do not crawl directories for which we do not have permissions - with `Hakyll.Core.Util.File.getRecursiveContents`. This used to +- Do not crawl directories for which we do not have permissions+ with `Hakyll.Core.Util.File.getRecursiveContents`. This used to throw an exception. - Do not return broken symbolic links from `Hakyll.Core.Util.File.getRecursiveContents`. This used to cause
hakyll.cabal view
@@ -1,5 +1,5 @@ Name: hakyll-Version: 4.16.6.0+Version: 4.16.7.0 Synopsis: A static website compiler library Description:@@ -191,7 +191,7 @@ binary >= 0.5 && < 0.10, blaze-html >= 0.5 && < 0.10, bytestring >= 0.9 && < 0.13,- containers >= 0.3 && < 0.8,+ containers >= 0.3 && < 0.9, data-default >= 0.4 && < 0.9, deepseq >= 1.3 && < 1.6, directory >= 1.2.7.0 && < 1.4,@@ -201,7 +201,7 @@ lrucache >= 1.1.1 && < 1.3, mtl >= 1 && < 2.4, network-uri >= 2.6 && < 2.7,- optparse-applicative >= 0.12 && < 0.19,+ optparse-applicative >= 0.12 && < 0.20, parsec >= 3.0 && < 3.2, process >= 1.6 && < 1.7, random >= 1.0 && < 1.4,@@ -215,7 +215,8 @@ time-locale-compat >= 0.1 && < 0.2, vector >= 0.11 && < 0.14, wai-app-static >= 3.1 && < 3.2,- yaml >= 0.8.11 && < 0.12+ yaml >= 0.8.11 && < 0.12,+ xml-conduit >= 1.0 && < 1.11 If flag(previewServer) Build-depends:@@ -252,7 +253,7 @@ Other-Modules: Hakyll.Web.Pandoc.Binary Build-Depends:- pandoc >= 2.11 && < 2.20 || >= 3.0 && < 3.7,+ pandoc >= 2.11 && < 2.20 || >= 3.0 && < 3.8, pandoc-types >= 1.22 && < 1.24 Cpp-options: -DUSE_PANDOC@@ -281,11 +282,12 @@ Hakyll.Web.Tags.Tests Hakyll.Web.Template.Context.Tests Hakyll.Web.Template.Tests+ Hakyll.Web.Feed.Tests TestSuite.Util Build-Depends: hakyll,- QuickCheck >= 2.8 && < 2.16,+ QuickCheck >= 2.8 && < 2.17, tasty >= 0.11 && < 1.6, tasty-golden >= 2.3 && < 2.4, tasty-hunit >= 0.9 && < 0.11,@@ -294,7 +296,7 @@ aeson >= 1.0 && < 1.6 || >= 2.0 && < 2.3, base >= 4.12 && < 5, bytestring >= 0.9 && < 0.13,- containers >= 0.3 && < 0.8,+ containers >= 0.3 && < 0.9, filepath >= 1.0 && < 1.6, tagsoup >= 0.13.1 && < 0.15, yaml >= 0.8.11 && < 0.12@@ -318,7 +320,7 @@ Cpp-options: -DUSE_PANDOC Build-Depends:- pandoc >= 2.11 && < 2.20 || >= 3.0 && < 3.7,+ pandoc >= 2.11 && < 2.20 || >= 3.0 && < 3.8, pandoc-types >= 1.22 && < 1.24 @@ -353,5 +355,5 @@ base >= 4.12 && < 5, directory >= 1.0 && < 1.4, filepath >= 1.0 && < 1.6,- pandoc >= 2.11 && < 2.20 || >= 3.0 && < 3.7,+ pandoc >= 2.11 && < 2.20 || >= 3.0 && < 3.8, pandoc-types >= 1.22 && < 1.24
lib/Hakyll/Core/Util/String.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-} -------------------------------------------------------------------------------- -- | Miscellaneous string manipulation functions. module Hakyll.Core.Util.String@@ -13,7 +13,6 @@ -------------------------------------------------------------------------------- import Data.Char (isSpace) import Data.List (isPrefixOf)-import Data.Maybe (listToMaybe) import Text.Regex.TDFA ((=~~)) @@ -33,12 +32,10 @@ -> String -- ^ Result replaceAll pattern f source = replaceAll' source where- replaceAll' src = case listToMaybe (src =~~ pattern) of- Nothing -> src- Just (o, l) ->- let (before, tmp) = splitAt o src- (capture, after) = splitAt l tmp- in before ++ f capture ++ replaceAll' after+ replaceAll' "" = ""+ replaceAll' src = case src =~~ pattern of+ Nothing -> src+ Just (before, capture, after) -> before ++ f capture ++ replaceAll' after --------------------------------------------------------------------------------@@ -49,11 +46,10 @@ -> [String] -- ^ Result splitAll pattern = filter (not . null) . splitAll' where- splitAll' src = case listToMaybe (src =~~ pattern) of- Nothing -> [src]- Just (o, l) ->- let (before, tmp) = splitAt o src- in before : splitAll' (drop l tmp)+ splitAll' "" = []+ splitAll' src = case src =~~ pattern of+ Nothing -> [src]+ Just (before, _::String, after) -> before : splitAll' after
lib/Hakyll/Web/Feed.hs view
@@ -19,30 +19,44 @@ -- -- In addition, the posts should be named according to the rules for -- 'Hakyll.Web.Template.Context.dateField'+--+-- Note that for XML-based feeds (i.e. Atom and RSS) field values are not escaped!+-- However, the default 'renderRss' and 'renderAtom' functions will validate the+-- produced XML. Use the -NoValidate functions instead if you need to skip this+-- validation. module Hakyll.Web.Feed ( FeedConfiguration (..) , renderRss+ , renderRssNoValidate , renderAtom+ , renderAtomNoValidate , renderJson , renderRssWithTemplates+ , renderRssWithTemplatesNoValidate , renderAtomWithTemplates+ , renderAtomWithTemplatesNoValidate , renderJsonWithTemplates+ , validateXMLFeed ) where -------------------------------------------------------------------------------- import Hakyll.Core.Compiler+import Hakyll.Core.Compiler.Internal (compilerThrow) import Hakyll.Core.Item-import Hakyll.Core.Util.String (replaceAll)+import Hakyll.Core.Util.String (replaceAll) import Hakyll.Web.Template import Hakyll.Web.Template.Context import Hakyll.Web.Template.List ---------------------------------------------------------------------------------import Data.FileEmbed (makeRelativeToProject)-import System.FilePath ((</>))-import Text.Printf (printf)+import Data.FileEmbed (makeRelativeToProject)+import System.FilePath ((</>))+import Text.Printf (printf)+import Control.Exception (displayException)+import Text.XML (parseText, def)+import qualified Data.Text.Lazy as T --------------------------------------------------------------------------------@@ -161,35 +175,89 @@ XmlFeed -> id JsonFeed -> mapContextBy (== "description") escapeString + --------------------------------------------------------------------------------+-- | Validate that a feed contains only correct XML.+validateXMLFeed :: Item String -> Compiler (Item String)+validateXMLFeed rendered = case parseText def $ T.pack (itemBody rendered) of+ Right _ -> pure rendered+ Left err -> compilerThrow+ ["Generated feed contains invalid XML (perhaps you id not escape a metadata field?)",+ displayException err]+++-------------------------------------------------------------------------------- -- | Render an RSS feed using given templates with a number of items.-renderRssWithTemplates ::+--+-- The resulting feed will not be validated. Prefer to use 'renderRssWithTemplates'+-- when possible.+--+-- @since 4.16.7.0+renderRssWithTemplatesNoValidate :: Template -- ^ Feed template -> Template -- ^ Item template -> FeedConfiguration -- ^ Feed configuration -> Context String -- ^ Item context -> [Item String] -- ^ Feed items -> Compiler (Item String) -- ^ Resulting feed-renderRssWithTemplates feedTemplate itemTemplate config context = renderFeed+renderRssWithTemplatesNoValidate feedTemplate itemTemplate config context = renderFeed XmlFeed feedTemplate itemTemplate config (makeItemContext "%a, %d %b %Y %H:%M:%S UT" context) --------------------------------------------------------------------------------+-- | Render an RSS feed using given templates with a number of items.+--+-- The resulting RSS feed will be validated automatically.+renderRssWithTemplates ::+ Template -- ^ Feed template+ -> Template -- ^ Item template+ -> FeedConfiguration -- ^ Feed configuration+ -> Context String -- ^ Item context+ -> [Item String] -- ^ Feed items+ -> Compiler (Item String) -- ^ Resulting feed+renderRssWithTemplates feedTemplate itemTemplate config context items =+ renderRssWithTemplatesNoValidate feedTemplate itemTemplate config context items+ >>= validateXMLFeed+++-------------------------------------------------------------------------------- -- | Render an Atom feed using given templates with a number of items.-renderAtomWithTemplates ::+--+-- The resulting feed will not be validated. Prefer to use 'renderAtomWithTemplates'+-- when possible.+--+-- @since 4.16.7.0+renderAtomWithTemplatesNoValidate :: Template -- ^ Feed template -> Template -- ^ Item template -> FeedConfiguration -- ^ Feed configuration -> Context String -- ^ Item context -> [Item String] -- ^ Feed items -> Compiler (Item String) -- ^ Resulting feed-renderAtomWithTemplates feedTemplate itemTemplate config context = renderFeed+renderAtomWithTemplatesNoValidate feedTemplate itemTemplate config context items = renderFeed XmlFeed feedTemplate itemTemplate config (makeItemContext "%Y-%m-%dT%H:%M:%SZ" context)+ items --------------------------------------------------------------------------------+-- | Render an Atom feed using given templates with a number of items.+--+-- The resulting Atom feed will be validated automatically.+renderAtomWithTemplates ::+ Template -- ^ Feed template+ -> Template -- ^ Item template+ -> FeedConfiguration -- ^ Feed configuration+ -> Context String -- ^ Item context+ -> [Item String] -- ^ Feed items+ -> Compiler (Item String) -- ^ Resulting feed+renderAtomWithTemplates feedTemplate itemTemplate config context items =+ renderAtomWithTemplatesNoValidate feedTemplate itemTemplate config context items+ >>= validateXMLFeed+++-------------------------------------------------------------------------------- -- | Render a JSON feed using given templates with a number of items. renderJsonWithTemplates :: Template -- ^ Feed template@@ -205,20 +273,54 @@ -------------------------------------------------------------------------------- -- | Render an RSS feed with a number of items.+--+-- The resulting feed will not be validated. Prefer to use 'renderRss'+-- when possible.+--+-- @since 4.16.7.0+renderRssNoValidate :: FeedConfiguration -- ^ Feed configuration+ -> Context String -- ^ Item context+ -> [Item String] -- ^ Feed items+ -> Compiler (Item String) -- ^ Resulting feed+renderRssNoValidate = renderRssWithTemplatesNoValidate rssTemplate rssItemTemplate+++--------------------------------------------------------------------------------+-- | Render an RSS feed with a number of items.+--+-- The resulting RSS feed will be validated automatically. renderRss :: FeedConfiguration -- ^ Feed configuration -> Context String -- ^ Item context -> [Item String] -- ^ Feed items -> Compiler (Item String) -- ^ Resulting feed-renderRss = renderRssWithTemplates rssTemplate rssItemTemplate+renderRss config context items = renderRssNoValidate config context items+ >>= validateXMLFeed -------------------------------------------------------------------------------- -- | Render an Atom feed with a number of items.+--+-- The resulting feed will not be validated. Prefer to use 'renderAtom'+-- when possible.+--+-- @since 4.16.7.0+renderAtomNoValidate :: FeedConfiguration -- ^ Feed configuration+ -> Context String -- ^ Item context+ -> [Item String] -- ^ Feed items+ -> Compiler (Item String) -- ^ Resulting feed+renderAtomNoValidate = renderAtomWithTemplatesNoValidate atomTemplate atomItemTemplate+++--------------------------------------------------------------------------------+-- | Render an Atom feed with a number of items.+--+-- The resulting Atom feed will be validated automatically. renderAtom :: FeedConfiguration -- ^ Feed configuration -> Context String -- ^ Item context -> [Item String] -- ^ Feed items -> Compiler (Item String) -- ^ Resulting feed-renderAtom = renderAtomWithTemplates atomTemplate atomItemTemplate+renderAtom config context items = renderAtomNoValidate config context items+ >>= validateXMLFeed --------------------------------------------------------------------------------
lib/Hakyll/Web/Pandoc.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} -------------------------------------------------------------------------------- -- | Module exporting convenient pandoc bindings module Hakyll.Web.Pandoc@@ -67,6 +68,11 @@ MediaWiki -> readMediaWiki ro OrgMode -> readOrg ro Rst -> readRST ro+-- This preprocessing instruction can be dropped+-- once the minimum supported GHC version is 8.10+#if MIN_VERSION_pandoc(3,1,3)+ Typst -> readTypst ro+#endif Textile -> readTextile ro _ -> error $ "Hakyll.Web.readPandocWith: I don't know how to read a file of " ++
lib/Hakyll/Web/Pandoc/FileType.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} -------------------------------------------------------------------------------- -- | A module dealing with pandoc file extensions and associated file types module Hakyll.Web.Pandoc.FileType@@ -33,6 +34,11 @@ | PlainText | Rst | Textile+-- This preprocessing instruction can be dropped+-- once the minimum supported GHC version is 8.10+#if MIN_VERSION_pandoc(3,1,3)+ | Typst+#endif deriving (Eq, Ord, Show, Read) @@ -66,6 +72,11 @@ fileType' _ ".text" = PlainText fileType' _ ".textile" = Textile fileType' _ ".txt" = PlainText+-- This preprocessing instruction can be dropped+-- once the minimum supported GHC version is 8.10+#if MIN_VERSION_pandoc(3,1,3)+ fileType' _ ".typ" = Typst+#endif fileType' _ ".wiki" = MediaWiki fileType' _ _ = Binary -- Treat unknown files as binary
tests/Hakyll/Core/Util/String/Tests.hs view
@@ -22,11 +22,23 @@ ] , fromAssertions "replaceAll"- [ "32 & 131" @=? replaceAll "0x[0-9]+" (show . readInt) "0x20 & 0x83"+ [ "foo-end" @=? replaceAll "begin" (const "foo") "begin-end"+ , "begin-foo" @=? replaceAll "end" (const "foo") "begin-end"+ , "no match" @=? replaceAll "abc" (const "foo") "no match"+ , "foo" @=? replaceAll ".*" (const "foo") "full match"+ , "empty pattern" @=? replaceAll "" (const "foo") "empty pattern"+ , "" @=? replaceAll "empty input" (const "foo") ""+ , "32 & 131" @=? replaceAll "0x[0-9]+" (show . readInt) "0x20 & 0x83" ] , fromAssertions "splitAll"- [ ["λ", "∀x.x", "hi"] @=? splitAll ", *" "λ, ∀x.x, hi"+ [ ["a", "b", "c"] @=? splitAll "," "a,,b,,,c,,"+ , ["abc", "def"] @=? splitAll "[0-9]+" "abc123def456"+ , ["no match"] @=? splitAll "," "no match"+ , [] @=? splitAll ".*" "full match"+ , ["empty pattern"] @=? splitAll "" "empty pattern"+ , [] @=? splitAll "empty input" ""+ , ["λ", "∀x.x", "hi"] @=? splitAll ", *" "λ, ∀x.x, hi" ] , fromAssertions "needlePrefix"
+ tests/Hakyll/Web/Feed/Tests.hs view
@@ -0,0 +1,68 @@+--------------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+module Hakyll.Web.Feed.Tests+ ( tests+ ) where+++--------------------------------------------------------------------------------+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.HUnit (Assertion, testCase)+++--------------------------------------------------------------------------------+import Hakyll.Core.Compiler+import Hakyll.Core.Provider+import Hakyll.Web.Feed+import Hakyll.Web.Template.Context+import TestSuite.Util+--------------------------------------------------------------------------------+tests :: TestTree+tests = testGroup "Hakyll.Web.Feed.Tests"+ [ testCase "validateSucceeds" validateSucceeds+ , testCase "validateFails" validateFails+ ]++validateFails :: Assertion+validateFails = do+ store <- newTestStore+ provider <- newTestProvider store++ item <- testCompilerDone store provider "example.md"+ $ makeItem (resourceFilePath provider "example.md")++ testCompilerError store provider "feed.xml"+ (renderRss feedConfiguration ctx [item])+ "Generated feed contains invalid XML (perhaps you id not escape a metadata field?)"+ cleanTestEnv+ where+ title = "invalid & not xml"+ ctx = constField "title" title `mappend`+ constField "description" "" `mappend`+ defaultContext++validateSucceeds :: Assertion+validateSucceeds = do+ store <- newTestStore+ provider <- newTestProvider store++ item <- testCompilerDone store provider "example.md"+ $ makeItem (resourceFilePath provider "example.md")++ _ <- testCompilerDone store provider "feed.xml"+ $ renderRss feedConfiguration ctx [item]+ cleanTestEnv+ where+ title = "valid xml"+ ctx = constField "title" title `mappend`+ constField "description" "" `mappend`+ defaultContext++feedConfiguration :: FeedConfiguration+feedConfiguration = FeedConfiguration+ { feedTitle = "test"+ , feedDescription = "test"+ , feedAuthorName = "test"+ , feedAuthorEmail = ""+ , feedRoot = "example.org"+ }
tests/TestSuite.hs view
@@ -30,6 +30,7 @@ import qualified Hakyll.Web.Template.Context.Tests import qualified Hakyll.Web.Template.Tests import qualified Hakyll.Web.Tags.Tests+import qualified Hakyll.Web.Feed.Tests --------------------------------------------------------------------------------@@ -55,4 +56,5 @@ , Hakyll.Web.Tags.Tests.tests , Hakyll.Web.Template.Context.Tests.tests , Hakyll.Web.Template.Tests.tests+ , Hakyll.Web.Feed.Tests.tests ]
web/site.hs view
@@ -68,9 +68,8 @@ -------------------------------------------------------------------------------- config :: Configuration config = defaultConfiguration- { deployCommand = "rsync --checksum -ave 'ssh -p 2222' \- \_site/* \- \jaspervdj@jaspervdj.be:jaspervdj.be/hakyll/"+ { deployCommand =+ "rsync --checksum -av _site/* anmitsu:jaspervdj.be/hakyll/" }