-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A markup parser. -- -- A markup parser and printer, from and to strict bytestrings, optimised -- for speed. @package markup-parse @version 0.1.0.1 -- | Various flatparse helpers and combinators. module MarkupParse.FlatParse -- | Warnings covering leftovers, Errs and Fail -- --
-- >>> runParserWarn ws " x" -- These (ParserLeftover "x") ' ' ---- --
-- >>> runParserWarn ws "x" -- This ParserUncaught ---- --
-- >>> runParserWarn (ws `cut` "no whitespace") "x" -- This (ParserError "no whitespace") --data ParserWarning ParserLeftover :: ByteString -> ParserWarning ParserError :: ByteString -> ParserWarning ParserUncaught :: ParserWarning -- | run a Parser, throwing away leftovers. Nothing on Fail or -- Err. -- --
-- >>> runParserMaybe ws "x" -- Nothing ---- --
-- >>> runParserMaybe ws " x" -- Just ' ' --runParserMaybe :: Parser e a -> ByteString -> Maybe a -- | run a Parser, throwing away leftovers. Returns Left on Fail or -- Err. -- --
-- >>> runParserEither ws " x" -- Right ' ' --runParserEither :: IsString e => Parser e a -> ByteString -> Either e a -- | Run parser, returning leftovers and errors as ParserWarnings. -- --
-- >>> runParserWarn ws " " -- That ' ' ---- --
-- >>> runParserWarn ws "x" -- This ParserUncaught ---- --
-- >>> runParserWarn ws " x" -- These (ParserLeftover "x") ' ' --runParserWarn :: Parser ByteString a -> ByteString -> These ParserWarning a -- | Run parser, discards leftovers & throws an error on failure. -- --
-- >>> runParser_ ws " " -- ' ' ---- --
-- >>> runParser_ ws "x" -- *** Exception: uncaught parse error -- ... --runParser_ :: Parser String a -> ByteString -> a -- | Run a parser. runParser :: Parser e a -> ByteString -> Result e a -- | The type of pure parsers. type Parser = ParserT PureMode -- | Higher-level boxed data type for parsing results. data Result e a -- | Contains return value and unconsumed input. OK :: a -> !ByteString -> Result e a -- | Recoverable-by-default failure. Fail :: Result e a -- | Unrecoverble-by-default error. Err :: !e -> Result e a -- | \n \t \f \r and space isWhitespace :: Char -> Bool -- | Consume whitespace. -- --
-- >>> runParser ws_ " \nx" -- OK () "x" ---- --
-- >>> runParser ws_ "x" -- OK () "x" --ws_ :: Parser e () -- | single whitespace -- --
-- >>> runParser ws " \nx" -- OK ' ' "\nx" --ws :: Parser e Char -- | multiple whitespace -- --
-- >>> runParser wss " \nx" -- OK " \n" "x" ---- --
-- >>> runParser wss "x" -- Fail --wss :: Parser e ByteString -- | Parse whilst not a specific character -- --
-- >>> runParser (nota 'x') "abcxyz" -- OK "abc" "xyz" --nota :: Char -> Parser e ByteString -- | Parse whilst satisfying a predicate. -- --
-- >>> runParser (isa (=='x')) "xxxabc" -- OK "xxx" "abc" --isa :: (Char -> Bool) -> Parser e ByteString -- | single quote -- --
-- >>> runParserMaybe sq "'" -- Just () --sq :: ParserT st e () -- | double quote -- --
-- >>> runParserMaybe dq "\"" -- Just () --dq :: ParserT st e () -- | A double-quoted string. wrappedDq :: Parser b ByteString -- | A single-quoted string. wrappedSq :: Parser b ByteString -- | A single-quoted or double-quoted string. -- --
-- >>> runParserMaybe wrappedQ "\"quoted\"" -- Just "quoted" ---- --
-- >>> runParserMaybe wrappedQ "'quoted'" -- Just "quoted" --wrappedQ :: Parser e ByteString -- | A single-quoted or double-quoted wrapped parser. -- --
-- >>> runParser (wrappedQNoGuard (many $ satisfy (/= '"'))) "\"name\"" -- OK "name" "" ---- -- Will consume quotes if the underlying parser does. -- --
-- >>> runParser (wrappedQNoGuard (many anyChar)) "\"name\"" -- Fail --wrappedQNoGuard :: Parser e a -> Parser e a -- | xml production [25] -- --
-- >>> runParserMaybe eq " = " -- Just () ---- --
-- >>> runParserMaybe eq "=" -- Just () --eq :: Parser e () -- | some with a separator -- --
-- >>> runParser (sep ws (many (satisfy (/= ' ')))) "a b c" -- OK ["a","b","c"] "" --sep :: Parser e s -> Parser e a -> Parser e [a] -- | parser bracketed by two other parsers -- --
-- >>> runParser (bracketed ($(char '[')) ($(char ']')) (many (satisfy (/= ']')))) "[bracketed]" -- OK "bracketed" "" --bracketed :: Parser e b -> Parser e b -> Parser e a -> Parser e a -- | Bracketed by square brackets. -- --
-- >>> runParser bracketedSB "[bracketed]" -- OK "bracketed" "" --bracketedSB :: Parser e [Char] -- | parser wrapped by another parser -- --
-- >>> runParser (wrapped ($(char '"')) (many (satisfy (/= '"')))) "\"wrapped\"" -- OK "wrapped" "" --wrapped :: Parser e () -> Parser e a -> Parser e a -- | A single digit -- -- runParserMaybe digit "5" Just 5 digit :: Parser e Int -- | (unsigned) Int parser -- --
-- >>> runParserMaybe int "567" -- Just 567 --int :: Parser e Int -- |
-- >>> runParser double "1.234x" -- OK 1.234 "x" ---- --
-- >>> runParser double "." -- Fail ---- --
-- >>> runParser double "123" -- OK 123.0 "" ---- --
-- >>> runParser double ".123" -- OK 0.123 "" ---- --
-- >>> runParser double "123." -- OK 123.0 "" --double :: Parser e Double -- | Parser for a signed prefix to a number. >>> runParser (signed -- double) "-1.234x" OK (-1.234) "x" signed :: Num b => Parser e b -> Parser e b -- | byteStringOf but using withSpan internally. Doesn't seems -- faster... byteStringOf' :: Parser e a -> Parser e ByteString -- | comma parser comma :: Parser e () instance Control.DeepSeq.NFData MarkupParse.FlatParse.ParserWarning instance GHC.Generics.Generic MarkupParse.FlatParse.ParserWarning instance GHC.Classes.Ord MarkupParse.FlatParse.ParserWarning instance GHC.Show.Show MarkupParse.FlatParse.ParserWarning instance GHC.Classes.Eq MarkupParse.FlatParse.ParserWarning -- | A Markup parser and printer of strict ByteStrings -- focused on optimising performance. Markup is a representation -- of data such as HTML, SVG or XML but the parsing is not always at -- standards. module MarkupParse -- | A list of Elements or Tree Tokens -- --
-- >>> markup Html "<foo class=\"bar\">baz</foo>"
-- That (Markup {elements = [Node {rootLabel = OpenTag StartTag "foo" [Attr {attrName = "class", attrValue = "bar"}], subForest = [Node {rootLabel = Content "baz", subForest = []}]}]})
--
newtype Markup
Markup :: [Element] -> Markup
[elements] :: Markup -> [Element]
-- | From a parsing pov, Html & Xml (& Svg) are close enough that
-- they share a lot of parsing logic, so that parsing and printing just
-- need some tweaking.
--
-- The xml parsing logic is based on the XML productions found in
-- https://www.w3.org/TR/xml/
--
-- The html parsing was based on a reading of html-parse, but
-- ignores the various 'x00' to 'xfffd' & eof directives that form
-- part of the html standards.
data Standard
Html :: Standard
Xml :: Standard
-- | Convert bytestrings to Markup
--
--
-- >>> markup Html "<foo><br></foo><baz"
-- These [MarkupParser (ParserLeftover "<baz")] (Markup {elements = [Node {rootLabel = OpenTag StartTag "foo" [], subForest = [Node {rootLabel = OpenTag StartTag "br" [], subForest = []}]}]})
--
markup :: Standard -> ByteString -> Warn Markup
-- | markup but errors on warnings.
markup_ :: Standard -> ByteString -> Markup
-- | Indented 0 puts newlines in between the tags.
data RenderStyle
Compact :: RenderStyle
Indented :: Int -> RenderStyle
-- | Convert Markup to bytestrings
--
-- -- >>> markdown (Indented 4) Html (markup_ Html [i|<foo><br></foo>|]) -- That "<foo>\n <br>\n</foo>" --markdown :: RenderStyle -> Standard -> Markup -> Warn ByteString -- | Convert Markup to ByteString and error on warnings. -- --
-- >>> B.putStr $ markdown_ (Indented 4) Html (markup_ Html [i|<foo><br></foo>|]) -- <foo> -- <br> -- </foo> --markdown_ :: RenderStyle -> Standard -> Markup -> ByteString -- | Concatenate sequential content and normalize attributes; unwording -- class values and removing duplicate attributes (taking last). -- --
-- >>> B.putStr $ warnError $ markdown Compact Xml $ normalize (markup_ Xml [i|<foo class="a" class="b" bar="first" bar="last"/>|]) -- <foo bar="last" class="a b"/> --normalize :: Markup -> Markup -- | Normalise Content in Markup, concatenating adjacent Content, and -- removing mempty Content. -- --
-- >>> normContent $ content "a" <> content "" <> content "b"
-- Markup {elements = [Node {rootLabel = Content "ab", subForest = []}]}
--
normContent :: Markup -> Markup
-- | Check for well-formedness and return warnings encountered.
--
-- -- >>> wellFormed Html $ Markup [Node (Comment "") [], Node (EndTag "foo") [], Node (OpenTag EmptyElemTag "foo" []) [Node (Content "bar") []], Node (OpenTag EmptyElemTag "foo" []) []] -- [EmptyContent,EndTagInTree,LeafWithChildren,BadEmptyElemTag] --wellFormed :: Standard -> Markup -> [MarkupWarning] -- | Are the trees in the markup well-formed? isWellFormed :: Standard -> Markup -> Bool -- | markup-parse generally tries to continue on parse errors, and return -- what has/can still be parsed, together with any warnings. data MarkupWarning -- | A tag ending with "/>" that is not an element of selfClosers -- (Html only). BadEmptyElemTag :: MarkupWarning -- | A tag ending with "/>" that has children. Cannot happen in the -- parsing phase. SelfCloserWithChildren :: MarkupWarning -- | Only a StartTag can have child tokens. LeafWithChildren :: MarkupWarning -- | A CloseTag with a different name to the currently open StartTag. TagMismatch :: NameTag -> NameTag -> MarkupWarning -- | An EndTag with no corresponding StartTag. UnmatchedEndTag :: MarkupWarning -- | An EndTag with corresponding StartTag. UnclosedTag :: MarkupWarning -- | An EndTag should never appear in Markup EndTagInTree :: MarkupWarning -- | Empty Content, Comment, Decl or Doctype EmptyContent :: MarkupWarning -- | Badly formed declaration BadDecl :: MarkupWarning MarkupParser :: ParserWarning -> MarkupWarning -- | A type synonym for the common returning type of many functions. A -- common computation pipeline is to take advantage of the These -- Monad instance eg -- --
-- markup s bs = bs & (tokenize s >=> gather s) & second (Markup s) --type Warn a = These [MarkupWarning] a -- | Convert any warnings to an error -- --
-- >>> warnError $ (tokenize Html) "<foo" -- *** Exception: MarkupParser (ParserLeftover "<foo") -- ... --warnError :: Warn a -> a -- | Returns Left on any warnings -- --
-- >>> warnEither $ (tokenize Html) "<foo><baz" -- Left [MarkupParser (ParserLeftover "<baz")] --warnEither :: Warn a -> Either [MarkupWarning] a -- | Returns results, if any, ignoring warnings. -- --
-- >>> warnMaybe $ (tokenize Html) "<foo><baz" -- Just [OpenTag StartTag "foo" []] --warnMaybe :: Warn a -> Maybe a -- | Most functions return a Markup rather than an Element -- because it is more ergonimc to use the free monoid wrap (aka a list) -- in preference to returning a 'Maybe Element', say. type Element = Tree Token -- | Create a Markup element from a NameTag and attributes that wraps some -- other Markup. -- --
-- >>> element "div" [] (element_ "br" [])
-- Markup {elements = [Node {rootLabel = OpenTag StartTag "div" [], subForest = [Node {rootLabel = OpenTag StartTag "br" [], subForest = []}]}]}
--
element :: NameTag -> [Attr] -> Markup -> Markup
-- | Create a Markup element from a NameTag and attributes that doesn't
-- wrap some other Markup. OpenTagType is StartTag. Use emptyElem
-- if you want to create a EmptyElemTag.
--
--
-- >>> (element_ "br" [])
-- Markup {elements = [Node {rootLabel = OpenTag StartTag "br" [], subForest = []}]}
--
element_ :: NameTag -> [Attr] -> Markup
-- | Create a Markup element from a NameTag and attributes using
-- EmptyElemTag, that doesn't wrap some other Markup. No checks are made
-- on whether this creates well-formed Markup.
--
--
-- >>> emptyElem "br" []
-- Markup {elements = [Node {rootLabel = OpenTag EmptyElemTag "br" [], subForest = []}]}
--
emptyElem :: NameTag -> [Attr] -> Markup
-- | Create a Markup element from a NameTag and attributes that wraps some
-- Content. No escaping is performed.
--
--
-- >>> elementc "div" [] "content"
-- Markup {elements = [Node {rootLabel = OpenTag StartTag "div" [], subForest = [Node {rootLabel = Content "content", subForest = []}]}]}
--
elementc :: NameTag -> [Attr] -> ByteString -> Markup
-- | Create a Markup element from a bytestring, escaping the usual
-- characters.
--
--
-- >>> content "<content>"
-- Markup {elements = [Node {rootLabel = Content "<content>", subForest = []}]}
--
content :: ByteString -> Markup
-- | Create a Markup element from a bytestring, not escaping the usual
-- characters.
--
--
-- >>> contentRaw "<content>"
-- Markup {elements = [Node {rootLabel = Content "<content>", subForest = []}]}
--
--
-- -- >>> markup_ Html $ markdown_ Compact Html $ contentRaw "<content>" -- *** Exception: UnclosedTag -- ... --contentRaw :: ByteString -> Markup -- | Name of token type NameTag = ByteString -- | Html tags that self-close selfClosers :: [NameTag] -- | Append attributes to the existing Token attribute list. addAttrs :: [Attr] -> Token -> Maybe Token -- | Standard Html Doctype -- --
-- >>> markdown_ Compact Html doctypeHtml -- "<!DOCTYPE html>" --doctypeHtml :: Markup -- | Standard Xml Doctype -- --
-- >>> markdown_ Compact Xml doctypeXml -- "<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" --doctypeXml :: Markup -- | Name of an attribute. type AttrName = ByteString -- | Value of an attribute. "" is equivalent to true with respect to -- boolean attributes. type AttrValue = ByteString -- | An attribute of a tag -- -- In parsing, boolean attributes, which are not required to have a value -- in HTML, will be set a value of "", which is ok. But this will then be -- rendered. -- --
-- >>> detokenize Html <$> tokenize_ Html [i|<input checked>|] -- ["<input checked=\"\">"] --data Attr Attr :: !AttrName -> !AttrValue -> Attr [attrName] :: Attr -> !AttrName [attrValue] :: Attr -> !AttrValue -- | Parse attributions attrsP :: Standard -> Parser a [Attr] -- | Parse a tag name. Each standard is slightly different. nameP :: Standard -> Parser e ByteString -- | Whether an opening tag is a start tag or an empty element tag. data OpenTagType StartTag :: OpenTagType EmptyElemTag :: OpenTagType -- | A Markup token -- --
-- >>> runParser_ (many (tokenP Html)) [i|<foo>content</foo>|] -- [OpenTag StartTag "foo" [],Content "content",EndTag "foo"] ---- --
-- >>> runParser_ (tokenP Xml) [i|<foo/>|] -- OpenTag EmptyElemTag "foo" [] ---- --
-- >>> runParser_ (tokenP Html) "<!-- Comment -->" -- Comment " Comment " ---- --
-- >>> runParser_ (tokenP Xml) [i|<?xml version="1.0" encoding="UTF-8"?>|]
-- Decl "xml" [Attr {attrName = "version", attrValue = " version=\"1.0\""},Attr {attrName = "encoding", attrValue = "UTF-8"}]
--
--
-- -- >>> runParser_ (tokenP Html) "<!DOCTYPE html>" -- Doctype "DOCTYPE html" ---- --
-- >>> runParser_ (tokenP Xml) "<!DOCTYPE foo [ declarations ]>" -- Doctype "DOCTYPE foo [ declarations ]" ---- --
-- >>> runParser (tokenP Html) [i|<foo a="a" b="b" c=c check>|]
-- OK (OpenTag StartTag "foo" [Attr {attrName = "a", attrValue = "a"},Attr {attrName = "b", attrValue = "b"},Attr {attrName = "c", attrValue = "c"},Attr {attrName = "check", attrValue = ""}]) ""
--
--
-- -- >>> runParser (tokenP Xml) [i|<foo a="a" b="b" c=c check>|] -- Fail --data Token -- | A tag. https://developer.mozilla.org/en-US/docs/Glossary/Tag OpenTag :: !OpenTagType -> !NameTag -> ![Attr] -> Token -- | A closing tag. EndTag :: !NameTag -> Token -- | The content between tags. Content :: !ByteString -> Token -- | Contents of a comment. Comment :: !ByteString -> Token -- | Contents of a declaration Decl :: !ByteString -> ![Attr] -> Token -- | Contents of a doctype declaration. Doctype :: !ByteString -> Token -- | Parse a bytestring into tokens -- --
-- >>> tokenize Html [i|<foo>content</foo>|] -- That [OpenTag StartTag "foo" [],Content "content",EndTag "foo"] --tokenize :: Standard -> ByteString -> Warn [Token] -- | tokenize but errors on warnings. tokenize_ :: Standard -> ByteString -> [Token] -- | A flatparse Token parser. -- --
-- >>> runParser (tokenP Html) "<foo>content</foo>" -- OK (OpenTag StartTag "foo" []) "content</foo>" --tokenP :: Standard -> Parser e Token -- | bytestring representation of Token. -- --
-- >>> detokenize Html (OpenTag StartTag "foo" []) -- "<foo>" --detokenize :: Standard -> Token -> ByteString -- | Gather together token trees from a token list, placing child elements -- in nodes and removing EndTags. -- --
-- >>> gather Html =<< tokenize Html "<foo class=\"bar\">baz</foo>"
-- That (Markup {elements = [Node {rootLabel = OpenTag StartTag "foo" [Attr {attrName = "class", attrValue = "bar"}], subForest = [Node {rootLabel = Content "baz", subForest = []}]}]})
--
gather :: Standard -> [Token] -> Warn Markup
-- | gather but errors on warnings.
gather_ :: Standard -> [Token] -> Markup
-- | Convert a markup into a token list, adding end tags.
--
--
-- >>> degather Html =<< markup Html "<foo class=\"bar\">baz</foo>"
-- That [OpenTag StartTag "foo" [Attr {attrName = "class", attrValue = "bar"}],Content "baz",EndTag "foo"]
--
degather :: Standard -> Markup -> Warn [Token]
-- | degather but errors on warning
degather_ :: Standard -> Markup -> [Token]
-- | xml production [24]
xmlVersionInfoP :: Parser e ByteString
-- | xml production [80]
xmlEncodingDeclP :: Parser e ByteString
-- | Xml production [32]
xmlStandaloneP :: Parser e ByteString
-- | xml production [26]
xmlVersionNumP :: Parser e ByteString
-- | xml production [81]
xmlEncNameP :: Parser e ByteString
-- | Xml yes/no
xmlYesNoP :: Parser e ByteString
-- | Convert a ByteString to an UTF8-encoded String.
utf8ToStr :: ByteString -> String
-- | Convert an UTF8-encoded String to a ByteString.
strToUtf8 :: String -> ByteString
-- | Escape a single character.
escapeChar :: Char -> ByteString
-- | Escape Content
--
-- -- >>> escape [i|<foo class="a" bar='b'>|] -- "<foo class="a" bar=&aposb&apos>" --escape :: ByteString -> ByteString -- | Non-empty, possibly infinite, multi-way trees; also known as rose -- trees. data Tree a Node :: a -> [Tree a] -> Tree a -- | label value [rootLabel] :: Tree a -> a -- | zero or more child trees [subForest] :: Tree a -> [Tree a] instance Data.TreeDiff.Class.ToExpr MarkupParse.Standard instance Control.DeepSeq.NFData MarkupParse.Standard instance GHC.Generics.Generic MarkupParse.Standard instance GHC.Classes.Ord MarkupParse.Standard instance GHC.Show.Show MarkupParse.Standard instance GHC.Classes.Eq MarkupParse.Standard instance Control.DeepSeq.NFData MarkupParse.MarkupWarning instance GHC.Generics.Generic MarkupParse.MarkupWarning instance GHC.Classes.Ord MarkupParse.MarkupWarning instance GHC.Show.Show MarkupParse.MarkupWarning instance GHC.Classes.Eq MarkupParse.MarkupWarning instance Data.TreeDiff.Class.ToExpr MarkupParse.OpenTagType instance Control.DeepSeq.NFData MarkupParse.OpenTagType instance GHC.Generics.Generic MarkupParse.OpenTagType instance GHC.Classes.Eq MarkupParse.OpenTagType instance GHC.Classes.Ord MarkupParse.OpenTagType instance GHC.Show.Show MarkupParse.OpenTagType instance GHC.Classes.Ord MarkupParse.Attr instance GHC.Classes.Eq MarkupParse.Attr instance GHC.Show.Show MarkupParse.Attr instance GHC.Generics.Generic MarkupParse.Attr instance Data.TreeDiff.Class.ToExpr MarkupParse.Token instance Control.DeepSeq.NFData MarkupParse.Token instance GHC.Generics.Generic MarkupParse.Token instance GHC.Classes.Eq MarkupParse.Token instance GHC.Classes.Ord MarkupParse.Token instance GHC.Show.Show MarkupParse.Token instance GHC.Base.Monoid MarkupParse.Markup instance GHC.Base.Semigroup MarkupParse.Markup instance Data.TreeDiff.Class.ToExpr MarkupParse.Markup instance Control.DeepSeq.NFData MarkupParse.Markup instance GHC.Generics.Generic MarkupParse.Markup instance GHC.Classes.Ord MarkupParse.Markup instance GHC.Classes.Eq MarkupParse.Markup instance GHC.Show.Show MarkupParse.Markup instance GHC.Generics.Generic MarkupParse.RenderStyle instance GHC.Show.Show MarkupParse.RenderStyle instance GHC.Classes.Eq MarkupParse.RenderStyle instance Control.DeepSeq.NFData MarkupParse.Attr instance Data.TreeDiff.Class.ToExpr MarkupParse.Attr -- | A patch function for tree-diff. module MarkupParse.Patch -- | ediff with unchanged sections filtered out -- --
-- >>> showPatch $ patch [1, 2, 3, 5] [0, 1, 2, 4, 6] -- "[+0, -3, +4, -5, +6]" --patch :: ToExpr a => a -> a -> Maybe (Edit EditExpr) -- | compare a markup file with a round-trip transformation. goldenPatch :: ToExpr a => (FilePath -> IO a) -> (a -> a) -> FilePath -> TestTree -- | Create a String representation of a patch. showPatch :: Maybe (Edit EditExpr) -> String