@@ -16,7 +16,13 @@ import Data.Text (Text)
16import Data.Tree
16import Data.Tree
17import Text.HTML.Parser
17import Text.HTML.Parser
19−
19+-- | construct a 'Forest' from a 'Token' list.
21+-- This code correctly handles void elements. Void elements are required to have a start tag and must not have an end tag. See 'nonClosing'.
23+-- This code does __not__ correctly handle optional tags. It assumes all optional start and end tags are present.
25+-- <https:\/\/www.w3.org\/TR\/html52\/syntax.html#optional-tags>
20tokensToForest :: [Token] -> Either ParseTokenForestError (Forest Token)
26tokensToForest :: [Token] -> Either ParseTokenForestError (Forest Token)
21tokensToForest = f (PStack [] [])
27tokensToForest = f (PStack [] [])
@@ -33,8 +39,15 @@ tokensToForest = f (PStack [] [])
33 Comment _ -> f (pushFlatSibling t pstack) ts
39 Comment _ -> f (pushFlatSibling t pstack) ts
34 Doctype _ -> f (pushFlatSibling t pstack) ts
40 Doctype _ -> f (pushFlatSibling t pstack) ts
42+-- | void elements which must not have an end tag
44+-- This list does not include the obsolete @\<command\>@ and @\<keygen\>@ elements.
46+-- @ nonClosing = ["br", "hr", "img", "meta", "area", "base", "col", "embed", "input", "link", "param", "source", "track", "wbr"] @
48+-- <https:\/\/www.w3.org\/TR\/html52\/syntax.html#void-elements>
36nonClosing :: [Text]
49nonClosing :: [Text]
37−nonClosing = ["br", "hr", "img", "meta", "area", "base", "col", "command", "embed", "input", "keygen", "link", "param", "source", "track", "wbr"]
50+nonClosing = ["br", "hr", "img", "meta", "area", "base", "col", "embed", "input", "link", "param", "source", "track", "wbr"]
39data ParseTokenForestError =
52data ParseTokenForestError =
40 ParseTokenForestErrorBracketMismatch PStack (Maybe Token)
53 ParseTokenForestErrorBracketMismatch PStack (Maybe Token)
@@ -58,10 +71,15 @@ popParent n pstack
58pushFlatSibling :: Token -> PStack -> PStack
71pushFlatSibling :: Token -> PStack -> PStack
59pushFlatSibling t (PStack ss ps) = PStack (Node t [] : ss) ps
72pushFlatSibling t (PStack ss ps) = PStack (Node t [] : ss) ps
61−
74+-- | convert a 'Forest' of 'Token' into a list of 'Token'.
76+-- This code correctly handles void elements. Void elements are required to have a start tag and must not have an end tag. See 'nonClosing'.
62tokensFromForest :: Forest Token -> [Token]
77tokensFromForest :: Forest Token -> [Token]
63tokensFromForest = mconcat . fmap tokensFromTree
78tokensFromForest = mconcat . fmap tokensFromTree
80+-- | convert a 'Tree' of 'Token' into a list of 'Token'.
82+-- This code correctly handles void elements. Void elements are required to have a start tag and must not have an end tag. See 'nonClosing'.
65tokensFromTree :: Tree Token -> [Token]
83tokensFromTree :: Tree Token -> [Token]
66tokensFromTree (Node o@(TagOpen n _) ts) | n `notElem` nonClosing
84tokensFromTree (Node o@(TagOpen n _) ts) | n `notElem` nonClosing
67 = [o] <> tokensFromForest ts <> [TagClose n]
85 = [o] <> tokensFromForest ts <> [TagClose n]