packages feed

pandoc-utils 0.4.0 → 0.5.0

raw patch · 8 files changed

+313/−126 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Text.Pandoc.Utils: class IsString a
- Text.Pandoc.Utils: class IsText a
- Text.Pandoc.Utils: class IsString s => ToString s
- Text.Pandoc.Utils: class IsString s => ToText s
- Text.Pandoc.Utils: fromString :: IsString a => String -> a
- Text.Pandoc.Utils: fromText :: IsText a => Text -> a
- Text.Pandoc.Utils: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.IsText [c]
- Text.Pandoc.Utils: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.ToString [c]
- Text.Pandoc.Utils: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.ToText [c]
- Text.Pandoc.Utils: instance Text.Pandoc.Utils.IsText Data.Text.Internal.Text
- Text.Pandoc.Utils: instance Text.Pandoc.Utils.ToString Data.Text.Internal.Text
- Text.Pandoc.Utils: instance Text.Pandoc.Utils.ToText Data.Text.Internal.Text
- Text.Pandoc.Utils: toString :: ToString s => s -> String
- Text.Pandoc.Utils: toText :: ToText s => s -> Text
+ Text.Pandoc.Filter.Utils: convertFilter :: ToPartialFilter Identity f p => f -> p -> p
+ Text.Pandoc.Filter.Utils: convertFilterM :: (Monad m, ToPartialFilter m f p) => f -> p -> m p
+ Text.Pandoc.Utils.String: class IsString a
+ Text.Pandoc.Utils.String: class IsText a
+ Text.Pandoc.Utils.String: class IsString s => ToString s
+ Text.Pandoc.Utils.String: class IsString s => ToText s
+ Text.Pandoc.Utils.String: fromString :: IsString a => String -> a
+ Text.Pandoc.Utils.String: fromText :: IsText a => Text -> a
+ Text.Pandoc.Utils.String: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.String.IsText [c]
+ Text.Pandoc.Utils.String: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.String.ToString [c]
+ Text.Pandoc.Utils.String: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.String.ToText [c]
+ Text.Pandoc.Utils.String: instance Text.Pandoc.Utils.String.IsText Data.Text.Internal.Text
+ Text.Pandoc.Utils.String: instance Text.Pandoc.Utils.String.ToString Data.Text.Internal.Text
+ Text.Pandoc.Utils.String: instance Text.Pandoc.Utils.String.ToText Data.Text.Internal.Text
+ Text.Pandoc.Utils.String: toString :: ToString s => s -> String
+ Text.Pandoc.Utils.String: toText :: ToText s => s -> Text
- Text.Pandoc.Filter.Utils: getConcatedFilter :: Foldable t => t (PartialFilter p) -> p -> p
+ Text.Pandoc.Filter.Utils: getConcatedFilter :: (Foldable t, Walkable a b) => t (PartialFilter a) -> b -> b
- Text.Pandoc.Filter.Utils: getConcatedFilterM :: (Foldable t, Monad m) => t (PartialFilterM m p) -> p -> m p
+ Text.Pandoc.Filter.Utils: getConcatedFilterM :: (Foldable t, Monad m, Walkable a b) => t (PartialFilterM m a) -> b -> m b

Files

CHANGELOG.md view
@@ -1,5 +1,13 @@ # Releases +## pandoc-utils 0.5.0 (2020-5-24)++- Reorganize documentations and API.+- Add new functions `convertFilter` and `convertFilterM` to convert between+  filter functions.+- Enable implicit conversion in `getConcatedFilter` and `getConcatedFilterM`.+- Add a module exporting all the utility functions provided by the package.+ ## pandoc-utils 0.4.0 (2020-5-24)  - Initial public release.
README.md view
@@ -1,11 +1,18 @@ # pandoc-utils +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/Krasjet/pandoc-utils/build)](https://github.com/Krasjet/pandoc-utils/actions?query=workflow%3Abuild)+[![Hackage](https://img.shields.io/hackage/v/pandoc-utils)](https://hackage.haskell.org/package/pandoc-utils)+ This package contains some useful functions for writing [Pandoc](https://pandoc.org/) filters and integrating Pandoc into Haskell-applications such as [Hakyll](https://jaspervdj.be/hakyll/). It provides a-composable wrapper for filters acting on nodes of the [Pandoc-AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html).+applications such as [Hakyll](https://jaspervdj.be/hakyll/). +It provides a composable wrapper for filters acting on nodes of the [Pandoc+AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html)+and a few functions to convert between filters. The package also provides an+attributes builder to work with attributes and some string utility functions to+handle the switch from `String` to `Text` in pandoc-types 1.20.+ ## Filter conversion/composition  As an example, let us look at the `behead` and `delink` filter from [Pandoc's@@ -22,9 +29,9 @@  Since `behead` has type `Block -> Block`, while `delink` has type `Inline -> [Inline]`, they are not naturally composable. However, this package provides a-utility function `mkFilter` to convert them into a `PandocFilter`.+utility function `mkFilter` to convert them into a wrapped `PandocFilter`. ```haskell-import Text.Pandoc.Filter.Utils+import Text.Pandoc.Utils  beheadFilter :: PandocFilter beheadFilter = mkFilter behead@@ -34,7 +41,7 @@ ``` `PandocFilter` is an alias for `PartialFilter Pandoc`, so you can also have `PartialFilter Inline`, etc. There is also a monadic version called-`PartialFilterM` for encapsulating monadic filters.+`PartialFilterM` for encapsulating monadic filter functions.  The `PandocFilter` is a monoid so you can do something like, ```haskell@@ -55,17 +62,27 @@   let doc' = applyFilter myFilter doc   writeHtml5String def doc' ```-or get an unwrapped `Pandoc -> Pandoc` filter using `getFilter` (this function-is also capable of doing implicit conversion from `PartialFilter a` to `b ->-b`).+or get an unwrapped `Pandoc -> Pandoc` filter function using `getFilter` (this+function is also capable of doing implicit conversion from `PartialFilter a` to+`b -> b`). ```haskell myPandocFilter :: Pandoc -> Pandoc myPandocFilter = getFilter myFilter ``` +If you just want to convert between Pandoc filter functions, e.g. `Inline ->+[Inline]` to `Pandoc -> Pandoc` without using the wrapped filter, there is also+`convertFilter` and `convertFilterM`+```haskell+delinkPandoc :: Pandoc -> Pandoc+delinkPandoc = convertFilter delink+```+This function is slightly more powerful than `walk` and `walkM` in that it is+also able to handle filter functions of type `a -> [a]` and `a -> m [a]`.+ For applying multiple filters, there is also a function called `applyFilters`,-which takes a list of filters and apply it to a `Pandoc` document (or subnode)-sequentially, from left to right.+which takes a list of wrapped filters and apply it to a `Pandoc` document (or+subnode) sequentially, from left to right. ```haskell myFilters :: [PandocFilter] myFilters =@@ -87,7 +104,7 @@ pandoc-utils also provides an attribute builder for handling attributes. You can create a new attributes by ```haskell-ghci> import Text.Pandoc.Filter.Utils.AttrBuilder+ghci> import Text.Pandoc.Utils ghci> import Text.Pandoc.Definition ghci> nullAttr `setId` "id" `addClass` "class" `addKVPair` ("key","value") ("id",["class"],[("key","value")])
pandoc-utils.cabal view
@@ -2,16 +2,20 @@ cabal-version:       2.0  name:                pandoc-utils-version:             0.4.0+version:             0.5.0 synopsis:   Utility functions to work with Pandoc in Haskell applications. description:   This package contains some useful functions for writing [Pandoc](https://pandoc.org/)-  filters and integrating Pandoc into Haskell applications such-  as [Hakyll](https://jaspervdj.be/hakyll/). It provides a-  composable wrapper for filters acting on nodes of the [Pandoc-  AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html).+  filters and integrating Pandoc into Haskell applications such as+  [Hakyll](https://jaspervdj.be/hakyll/) and web servers.   .+  It provides a composable wrapper for filters acting on nodes of the [Pandoc+  AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html)+  and a few functions to convert between filters. The package also provides an+  attributes builder to work with attributes and some string utility functions+  to handle the switch from 'String' to 'Text' in pandoc-types 1.20.+  .   For more examples, please see the [README](https://github.com/Krasjet/pandoc-utils) on GitHub. license:             MIT license-file:        LICENSE@@ -35,6 +39,7 @@   ghc-options:         -Wall   exposed-modules:       Text.Pandoc.Utils+      Text.Pandoc.Utils.String       Text.Pandoc.Filter.Utils       Text.Pandoc.Filter.Utils.AttrBuilder   build-depends:
src/Text/Pandoc/Filter/Utils.hs view
@@ -5,25 +5,37 @@ -- | This module contains some utility functions to work with different levels -- of Pandoc filters. For example, for the conversion from @'Inline' -> -- ['Inline']@ to @'Pandoc' -> 'Pandoc'@ filter.+--+-- If you don't need to compose filters and only want to convert between Pandoc+-- filter functions, just use 'convertFilter' and 'convertFilterM'.+--+-- However, if you are working with multiple Pandoc filters of different type+-- and want to compose them, this module also provides a monoid wrapper type+-- 'PartialFilterM', which I call a "wrapped filter", and a few functions to+-- apply, compose, and convert them. module Text.Pandoc.Filter.Utils (-  -- * Definitions-  PartialFilterM,+  -- * Filter function conversion+  convertFilter,+  convertFilterM,+  -- * Wrapped filter definitions   PartialFilter,-  PandocFilterM,   PandocFilter,-  -- * Filter application-  applyFilterM,+  PartialFilterM,+  PandocFilterM,+  -- * Filter function → Wrapped filter+  ToPartialFilter (..),+  mkConcatedFilter,+  -- * Wrapped filter application/composition   applyFilter,-  -- * Filter composition-  applyFiltersM,   applyFilters,-  -- * Filter conversion-  getFilterM,+  applyFilterM,+  applyFiltersM,+  -- * Wrapped filter → filter function   getFilter,-  getConcatedFilterM,   getConcatedFilter,-  ToPartialFilter (..),-  mkConcatedFilter,+  getFilterM,+  getConcatedFilterM,+  -- * Wrapped filter conversion   toFilterM,   ) where @@ -35,7 +47,8 @@  -- | @PartialFilterM m p@ is a wrapper for any monadic @p -> m p@ Pandoc -- filters acting on a subnode (e.g. 'Inline' or 'Block') of the 'Pandoc'--- abstract syntax tree.+-- abstract syntax tree. On this page, we will call it a "wrapped" filter to+-- distinguish it from filter functions @a -> m b@. -- -- * @m@: a monad. -- * @p@: the type of a subnode of 'Pandoc' (e.g. 'Inline').@@ -47,7 +60,8 @@  -- | @PartialFilter p@ is a wrapper for ordinary @p -> p@ Pandoc filters acting -- on a subnode (e.g. 'Inline' or 'Block') of the 'Pandoc' abstract syntax--- tree.+-- tree. On this page, we will call it a "wrapped" filter to distinguish it+-- from filter functions @a -> b@. -- -- * @p@: the type of a subnode of 'Pandoc' (e.g. 'Inline'). type PartialFilter = PartialFilterM Identity@@ -64,31 +78,39 @@ -- * @m@: a monad. type PandocFilterM m = PartialFilterM m Pandoc --- | Apply an ordinary filter to @p@, which returns @p@ directly.+-- | Apply a wrapped filter to @p@, which returns @p@ directly. applyFilter-  :: PartialFilter p -- ^ A wrapped partial filter.+  :: PartialFilter p -- ^ A wrapped filter.   -> p               -- ^ 'Pandoc' AST node.   -> p               -- ^ Transformed node. applyFilter = (runIdentity .) . applyFilterM --- | It is mostly the same as 'applyFilterM' and should be used when you don't--- need to apply the filter immediately. The only difference is that it will--- perform an implicit conversion if the requested filter function is of a--- different type.+-- | It is mostly the same as 'applyFilterM', which converts a wrapped monadic+-- filter to a monadic filter function, but it should be used when you don't+-- need to apply the filter immediately. There is a slight difference in that+-- it will perform an implicit conversion if the requested filter function is+-- of a different type.+--+-- For example, it can be used to convert a wrapped monadic filter+-- @'PartialFilterM' 'IO' 'Inline'@ to monadic filter function @'Block' -> 'IO'+-- 'Block'@. getFilterM   :: (Monad m, Walkable a b)-  => PartialFilterM m a -- ^ A wrapped partial filter on @a@.-  -> (b -> m b)         -- ^ Unwrapped filter function that can be directly applied to @b@.+  => PartialFilterM m a -- ^ A wrapped filter on @a@.+  -> (b -> m b)         -- ^ Filter function that can be directly applied to @b@. getFilterM = applyFilterM . mkFilter --- | It is mostly the same as 'applyFilter' and should be used when you don't--- need to apply the filter immediately. The only difference is that it will--- perform an implicit conversion if the requested filter function is of a--- different type.+-- | It is mostly the same as 'applyFilter', which converts a wrapped filter to+-- a filter function, but it should be used when you don't need to apply the+-- filter immediately. There is a slight difference in that it will perform an+-- implicit conversion if the requested filter function is of a different type.+--+-- For example, it can be used to convert a wrapped filter @'PartialFilter'+-- 'Inline'@ to filter function @'Block' -> 'Block'@. getFilter   :: (Walkable a b)   => PartialFilter a -- ^ A wrapped partial filter on @a@.-  -> (b -> b)        -- ^ Unwrapped filter function that can be directly applied to @b@.+  -> (b -> b)        -- ^ Filter function that can be directly applied to @b@. getFilter = applyFilter . mkFilter  -- | The 'Semigroup' instance of `PartialFilterM`. @f1 <> f2@ will apply @f1@@@ -103,11 +125,12 @@ -- | A helper typeclass used as a polymorphic constructor of 'PartialFilterM'. class ToPartialFilter m f p where   -- | The actual constructor of 'PartialFilterM'. It takes an ordinary filter-  -- function @a -> b@ and wraps it as a 'PartialFilterM'. It can also be used-  -- to convert between different types of @'PartialFilterM' m@.+  -- function @a -> b@ and wraps it as a wrapped filter 'PartialFilterM'. It+  -- can also be used to convert between different types of @'PartialFilterM'+  -- m@.   mkFilter-    :: f                  -- ^ A partial filter function, usually @a -> a@ for some @'Walkable' a p@.-    -> PartialFilterM m p -- ^ Wrapped partial Pandoc filter.+    :: f                  -- ^ A filter function, usually @a -> a@ for some @'Walkable' a p@.+    -> PartialFilterM m p -- ^ Wrapped Pandoc filter.  instance (Monad m, Walkable a p) => ToPartialFilter m (a -> a) p where   mkFilter = PartialFilterM . (return .) . walk@@ -126,55 +149,92 @@ instance (Monad m, Walkable a b) => ToPartialFilter m (PartialFilterM m a) b where   mkFilter = mkFilter . applyFilterM --- | Construct a 'PartialFilterM' from a list of filter functions of the same--- type. The final filter is concatenated from left to right such that the--- first element in the list will be applied first and the last element will be--- applied at the end.+-- | Construct a wrapped filter 'PartialFilterM' from a list of filter+-- functions of the same type. The final filter is concatenated from left to+-- right such that the first element in the list will be applied first and the+-- last element will be applied at the end.+--+-- For example, it can be used to convert an list of filter functions+-- @['Inline' -> ['Inline']]@ to a wrapped filter @'PandocFilter'@. mkConcatedFilter   :: (Monad m, ToPartialFilter m f p, Foldable t)   => t f                -- ^ A list of filter functions of the same type.   -> PartialFilterM m p -- ^ Concatenated filter. mkConcatedFilter = foldMap mkFilter --- | Convert an ordinary 'PartialFilter' to the monadic version+-- | Convert an ordinary wrapped filter 'PartialFilter' to the monadic version -- 'PartialFilterM'.+--+-- For example, it can be used to convert an ordinary wrapped filter+-- @'PartialFilter' 'Inline'@ to monadic wrapped filter @'PartialFilterM' 'IO'+-- 'Inline'@. toFilterM   :: (Monad m)   => PartialFilter p    -- ^ An ordinary filter.   -> PartialFilterM m p -- ^ The monadic version. toFilterM = PartialFilterM . (return .) . applyFilter --- | Apply a list of monadic partial filters sequentially, from left to--- right, i.e.  the first element in the list will be applied first and the--- last element will be applied at the end.+-- | Apply a list of monadic wrapped filters sequentially, from left to right,+-- i.e. the first element in the list will be applied first and the last+-- element will be applied at the end. applyFiltersM   :: (Foldable t, Monad m)-  => t (PartialFilterM m p) -- ^ A list of monadic partial filters.+  => t (PartialFilterM m p) -- ^ A list of monadic wrapped filters.   -> p                      -- ^ 'Pandoc' AST node.   -> m p                    -- ^ Transformed node. applyFiltersM = applyFilterM . fold --- | Apply a list of partial filters sequentially, from left to right, i.e.+-- | Apply a list of wrapped filters sequentially, from left to right, i.e. -- the first element in the list will be applied first and the last element -- will be applied at the end. applyFilters   :: (Foldable t)-  => t (PartialFilter p) -- ^ A list of partial filter.+  => t (PartialFilter p) -- ^ A list of wrapped filter.   -> p                   -- ^ 'Pandoc' AST node.   -> p                   -- ^ Transformed node. applyFilters = applyFilter . fold --- | An alias for 'applyFiltersM', used when the filter is not used--- immediately.+-- | It is mostly the same as 'applyFiltersM', which converts a list of wrapped+-- monadic filter to a monadic filter function, but it should be used when you+-- don't need to apply the filter immediately. There is a slight difference in+-- that it will perform an implicit conversion if the requested filter function+-- is of a different type.+--+-- For example, it can be used to convert a list of wrapped monadic filter+-- @['PartialFilterM' 'IO' 'Inline']@ to a filter function @'Block' -> 'IO'+-- 'Block'@. getConcatedFilterM-  :: (Foldable t, Monad m)-  => t (PartialFilterM m p) -- ^ A list of monadic partial filters.-  -> (p -> m p)             -- ^ Unwrapped monadic filter applicable to @p@ directly.-getConcatedFilterM = applyFiltersM+  :: (Foldable t, Monad m, Walkable a b)+  => t (PartialFilterM m a) -- ^ A list of monadic partial filters on @a@.+  -> (b -> m b)             -- ^ Monadic filter function applicable to @b@ directly.+getConcatedFilterM = applyFilterM . mkConcatedFilter --- | An alias for 'applyFilters', used when the filter is not used immediately.+-- | It is mostly the same as 'applyFilters', which converts a list of wrapped+-- filter to a filter function, but it should be used when you don't need to+-- apply the filter immediately. There is a slight difference in that it will+-- perform an implicit conversion if the requested filter function is of a+-- different type.+--+-- For example, it can be used to convert a list of wrapped filter+-- @['PartialFilter' 'Inline']@ to a filter function @'Block' -> 'Block'@. getConcatedFilter-  :: (Foldable t)-  => t (PartialFilter p) -- ^ A list of partial filter.-  -> (p -> p)            -- ^ Unwrapped filter applicable to @p@ directly.-getConcatedFilter = applyFilters+  :: (Foldable t, Walkable a b)+  => t (PartialFilter a) -- ^ A list of wrapped filter acting on @a@+  -> (b -> b)            -- ^ Filter function applicable to @b@ directly.+getConcatedFilter = applyFilter . mkConcatedFilter++-- | Conversion between monadic filter functions, e.g. from @'Inline' ->+-- 'IO' ['Inline']@ filter to @'Pandoc' -> 'IO' 'Pandoc'@ filter.+convertFilterM+  :: (Monad m, ToPartialFilter m f p)+  => f                -- ^ A monadic filter function.+  -> (p -> m p)       -- ^ Monadic filter function acting on @p@.+convertFilterM = applyFilterM . mkFilter++-- | Conversion between filter functions, e.g. from @'Inline' -> ['Inline']@+-- filter to @'Pandoc' -> 'Pandoc'@ filter.+convertFilter+  :: (ToPartialFilter Identity f p)+  => f        -- ^ A filter function.+  -> (p -> p) -- ^ Filter function acting on @p@.+convertFilter = applyFilter . mkFilter
src/Text/Pandoc/Filter/Utils/AttrBuilder.hs view
@@ -9,7 +9,7 @@   setId, ) where -import Text.Pandoc.Utils+import Text.Pandoc.Utils.String  import Data.Bifunctor         (bimap, first, second) import Data.Text              (Text)
src/Text/Pandoc/Utils.hs view
@@ -1,52 +1,13 @@-{-# LANGUAGE TypeFamilies #-}---- | Due to the switch from 'String' to 'Text' in pandoc-types 1.20, some--- legacy filters might not work in newer versions. This module contains some--- string conversion utility functions to make filters work in across different--- versions.+-- | This module exports all the utility functions provided by this package. module Text.Pandoc.Utils (-  -- * Conversions-  ToString (..),-  ToText (..),-  IsText (..),-  -- * Reexport from Data.String-  IsString (..),-  ) where--import qualified Data.Text as T--import Data.String (IsString (..))-import Data.Text   (Text)---- | A helper typeclass for converting 'String' and 'Text' to 'String'.-class IsString s => ToString s where-  -- | Convert strings to 'String'.-  toString :: s -> String--instance Char ~ c => ToString [c] where-  toString = id--instance ToString Text where-  toString = T.unpack---- | A helper typeclass for converting 'String' and 'Text' to 'Text'.-class IsString s => ToText s where-  -- | Convert strings to 'Text'.-  toText :: s -> Text--instance Char ~ c => ToText [c] where-  toText = T.pack--instance ToText Text where-  toText = id---- | A helper typeclass for converting 'Text' to either 'String' or 'Text'.-class IsText a where-  -- | Convert from 'Text' to strings-  fromText :: Text -> a--instance Char ~ c => IsText [c] where-  fromText = T.unpack+  -- * Filter utils+  module Text.Pandoc.Filter.Utils,+  -- * Attribute builders+  module Text.Pandoc.Filter.Utils.AttrBuilder,+  -- * String conversions+  module Text.Pandoc.Utils.String+) where -instance IsText Text where-  fromText = id+import Text.Pandoc.Filter.Utils+import Text.Pandoc.Filter.Utils.AttrBuilder+import Text.Pandoc.Utils.String
+ src/Text/Pandoc/Utils/String.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE TypeFamilies #-}++-- | Due to the switch from 'String' to 'Text' in pandoc-types 1.20, some+-- legacy filters might not work in newer versions. This module contains some+-- string conversion utility functions to make filters work in across different+-- versions.+module Text.Pandoc.Utils.String (+  -- * Conversions+  ToString (..),+  ToText (..),+  IsText (..),+  -- * Reexport from Data.String+  IsString (..),+  ) where++import qualified Data.Text as T++import Data.String (IsString (..))+import Data.Text   (Text)++-- | A helper typeclass for converting 'String' and 'Text' to 'String'.+class IsString s => ToString s where+  -- | Convert strings to 'String'.+  toString :: s -> String++instance Char ~ c => ToString [c] where+  toString = id++instance ToString Text where+  toString = T.unpack++-- | A helper typeclass for converting 'String' and 'Text' to 'Text'.+class IsString s => ToText s where+  -- | Convert strings to 'Text'.+  toText :: s -> Text++instance Char ~ c => ToText [c] where+  toText = T.pack++instance ToText Text where+  toText = id++-- | A helper typeclass for converting 'Text' to either 'String' or 'Text'.+class IsText a where+  -- | Convert from 'Text' to strings+  fromText :: Text -> a++instance Char ~ c => IsText [c] where+  fromText = T.unpack++instance IsText Text where+  fromText = id
test/Spec.hs view
@@ -12,8 +12,7 @@ import Test.Tasty import Test.Tasty.Hspec import Text.Pandoc.Definition-import Text.Pandoc.Filter.Utils-import Text.Pandoc.Filter.Utils.AttrBuilder+import Text.Pandoc.Utils  -- * Testing data @@ -118,6 +117,9 @@ beheadFilter :: PandocFilter beheadFilter = mkFilter behead +beheadPandoc :: Pandoc -> Pandoc+beheadPandoc = convertFilter behead+ delink :: Inline -> [Inline] delink (Link _ txt _) = txt delink x              = [x]@@ -125,6 +127,9 @@ delinkFilter :: PandocFilter delinkFilter = mkFilter delink +delinkPandoc :: Pandoc -> Pandoc+delinkPandoc = convertFilter delink+ myFilter :: PandocFilter myFilter = beheadFilter <> delinkFilter @@ -238,6 +243,41 @@       bl `shouldBe` expectedInlinePartial       s' `shouldBe` T.pack "abcd" +  describe "convertFilter" $ do+    it "converts a -> a filter to Pandoc -> Pandoc filter" $ do+      convertFilter capFilterInline docPara `shouldBe` expectedInline+      convertFilter unParaFilterBlock docPara `shouldBe` expectedBlock++    it "converts a -> a filter to b -> b partial filter" $+      convertFilter capFilterInline blockPara `shouldBe` expectedInlinePartial++    it "converts a -> [a] filter to Pandoc -> Pandoc filter" $ do+      convertFilter dupFilterInline docPara `shouldBe` expectedInlineL+      convertFilter dupFilterBlock docPara `shouldBe` expectedBlockL++    it "converts a -> [a] filter to b -> b partial filter" $+      convertFilter dupFilterInline blockPara `shouldBe` expectedInlinePartialL++    it "converts a -> m a filter to Pandoc -> m Pandoc filter" $ do+      let (doc, s) = runWriter $ convertFilterM extractFilterInlineM docPara+      doc `shouldBe` expectedInline+      s `shouldBe` T.pack "abcd"++    it "converts a -> m a filter to b -> m b filter" $ do+      let (bl, s) = runWriter $ convertFilterM extractFilterInlineM blockPara+      bl `shouldBe` expectedInlinePartial+      s `shouldBe` T.pack "abcd"++    it "converts a -> m [a] filter to Pandoc -> m Pandoc filter" $ do+      let (doc, s) = runWriter $ convertFilterM extractFilterInlineML docPara+      doc `shouldBe` expectedInlineL+      s `shouldBe` T.pack "abcd"++    it "converts a -> m [a] filter to b -> m b filter" $ do+      let (bl, s) = runWriter $ convertFilterM extractFilterInlineML blockPara+      bl `shouldBe` expectedInlinePartialL+      s `shouldBe` T.pack "abcd"+   describe "getFilter" $ do     it "converts PartialFilter a to a -> a" $ do       let fInline = mkFilter capFilterInline :: PartialFilter Inline@@ -294,12 +334,10 @@     it "applys merge correctly" $       applyFilter merge compPara2 `shouldBe` expectedMerge -  describe "applyFilters and monoid" $ do+  describe "applyFilters" $ do     it "applys PartialFilter composition from left to right" $ do       applyFilter (dup <> merge) compPara `shouldBe` expectedDupMerge       applyFilter (merge <> dup) compPara `shouldBe` expectedMergeDup-      applyFilters [dup, merge] compPara `shouldBe` expectedDupMerge-      applyFilters [merge, dup] compPara `shouldBe` expectedMergeDup      it "applys PartialFilterM composition from left to right" $ do       let (doc, s) = runWriter $ applyFilterM (extract <> toFilterM dup) compPara@@ -310,12 +348,58 @@       doc' `shouldBe` expectedDup       s' `shouldBe` T.pack "abcdabcd" +  describe "monoid instance" $ do+    it "applys PartialFilter composition from left to right" $ do+      applyFilters [dup, merge] compPara `shouldBe` expectedDupMerge+      applyFilters [merge, dup] compPara `shouldBe` expectedMergeDup++    it "applys PartialFilterM composition from left to right" $ do+      let (doc, s) = runWriter $ applyFiltersM [extract, toFilterM dup] compPara+      doc `shouldBe` expectedDup+      s `shouldBe` T.pack "abcd"++      let (doc', s') = runWriter $ applyFiltersM [toFilterM dup, extract] compPara+      doc' `shouldBe` expectedDup+      s' `shouldBe` T.pack "abcdabcd"++  let dupInl = mkFilter dupFilterInline     :: PartialFilter [Inline]+      mergeInl = mkFilter mergeFilterInline :: PartialFilter [Inline]+      extractInl = mkFilter extractFilter   :: PartialFilterM (Writer Text) [Inline]++  describe "getConcatedFilter" $ do+    it "converts [PartialFilter a] to a -> a, applied from left to right" $ do+      getConcatedFilter [dupInl, mergeInl] [Str "abcd"] `shouldBe` [Str "abcdabcd"]+      getConcatedFilter [mergeInl, dupInl] [Str "abcd"] `shouldBe` [Str "abcd", Str "abcd"]++    it "converts [PartialFilterM m a] to a -> m a, applied from left to right" $ do+      let (doc, s) = runWriter $ getConcatedFilterM [extractInl, toFilterM dupInl] [Str "abcd"]+      doc `shouldBe` [Str "abcd", Str "abcd"]+      s `shouldBe` T.pack "abcd"++      let (doc', s') = runWriter $ getConcatedFilterM [toFilterM dupInl, extractInl] [Str "abcd"]+      doc' `shouldBe` [Str "abcd", Str "abcd"]+      s' `shouldBe` T.pack "abcdabcd"++    it "converts [PartialFilter a] to b -> b, applied from left to right" $ do+      getConcatedFilter [dupInl, mergeInl] compPara `shouldBe` expectedDupMerge+      getConcatedFilter [mergeInl, dupInl] compPara `shouldBe` expectedMergeDup++    it "converts [PartialFilterM m a] to b -> m b, applied from left to right" $ do+      let (doc, s) = runWriter $ getConcatedFilterM [extractInl, toFilterM dupInl] compPara+      doc `shouldBe` expectedDup+      s `shouldBe` T.pack "abcd"++      let (doc', s') = runWriter $ getConcatedFilterM [toFilterM dupInl, extractInl] compPara+      doc' `shouldBe` expectedDup+      s' `shouldBe` T.pack "abcdabcd"+ readmeSpec :: Spec readmeSpec = parallel $   describe "readme example" $ do     it "processes filter examples correctly on AST level" $ do       applyFilters [beheadFilter, delinkFilter] readmeDoc `shouldBe` expectedDoc       applyFilter myFilter readmeDoc `shouldBe` expectedDoc+      (delinkPandoc . beheadPandoc) readmeDoc `shouldBe` expectedDoc      it "processes filter examples correctly on Text level" $ do       fromRight "" (mdToHtml readmeText) `shouldBe` expectedHtml