~alcinnz/haskell-stylist

186cbffac5c4f775ce015d7ed2a92279c4449644 — Adrian Cochrane 4 years ago 2277b56
Improve documentation, release version 1.2
M src/Data/CSS/Preprocessor/Conditions.hs => src/Data/CSS/Preprocessor/Conditions.hs +6 -0
@@ 1,4 1,8 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Evaluates conditional CSS @rules.
-- Parse a CSS stylesheet to `ConditionalStyles` to evaluate @document & @supports rules.
-- Call `loadImports` to resolve any @import rules to @media rules.
-- And call `resolve` to convert into another `StyleSheet` instance whilst resolving @media rules.
module Data.CSS.Preprocessor.Conditions(
        ConditionalStyles(..), conditionalStyles, ConditionalRule(..),
        extractImports, resolveImports, loadImports, resolve, testIsStyled,


@@ 102,6 106,8 @@ instance PropertyParser p => StyleSheet (ConditionalStyles p) where
    addAtRule self rule tokens = let (block, rest) = scanAtRule tokens in
        (addRule' self $ AtRule rule block, rest)

-- | Flags whether any style rules have been applied yet,
-- for the sake of evaluating "@document unstyled {...}".
testIsStyled :: ConditionalStyles p -> ConditionalStyles p
testIsStyled styles = styles { isUnstyled = null $ rules styles }


M src/Data/CSS/Preprocessor/Conditions/Expr.hs => src/Data/CSS/Preprocessor/Conditions/Expr.hs +19 -2
@@ 1,4 1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Evaluates CSS media queries for @import & @media.
-- INTERNAL MODULE
module Data.CSS.Preprocessor.Conditions.Expr(
        Expr, Op(..), parse, parse', eval, Datum(..)
    ) where


@@ 7,16 9,30 @@ import Data.CSS.Syntax.Tokens(Token(..))
import Data.Text.Internal (Text(..))
import Data.Text (stripPrefix)

-- | A parsed (post-order) expression.
type Expr = [Op]
data Op = And | Or | Not | Var Text | Tok Token | MkRatio | Func Text [Token]
    | Less | LessEq | Equal | Greater | GreaterEq deriving (Show, Eq)
-- | Operators understood by media queries.
data Op = And -- ^ Is true if both operands are true
    | Or -- ^ Is true if either operand is true
    | Not -- ^ Is true if it's operand isn't.
    | Var Text -- ^ Queries the value of an externally-specified parameter.
    | Tok Token -- ^ Tokens to be evaluated as specified by caller.
    | MkRatio -- ^ Pushes a ratio value to stack, for querying screensize.
    | Less -- ^ Is the left operand smaller than right?
    | LessEq -- ^ Is the left operand smaller or the same as right?
    | Equal -- ^ Are the operands the same?
    | Greater -- ^ Is the left operand bigger than right?
    | GreaterEq -- ^ Is the left operand bigger or the same as right?
    deriving (Show, Eq)

-- | Parses a media query to postorder form, returning the tokens after the given delimiter.
parse :: Token -> [Token] -> (Expr, [Token])
parse end toks = let (toks', rest) = break (== end) toks in (parse' toks' [], rest)

--------
---- Shunting Yard parser
--------
-- | Parses a media query to postorder form, given an operator stack.
parse' :: [Token] -> [(Op, Int)] -> Expr
parse' (Whitespace:toks) ops = parse' toks ops



@@ 58,6 74,7 @@ pushOp toks op b ops = parse' toks ((op, b):ops)
-- | Dynamic types for evaluating media queries.
data Datum = B Bool | N Float | Ratio Float Float deriving Eq

-- | Evaluates a media query with the given functions for evaluating vars & tokens.
eval :: (Text -> Datum) -> (Token -> Datum) -> Expr -> Bool
eval = eval' []


M src/Data/CSS/Style.hs => src/Data/CSS/Style.hs +2 -0
@@ 1,4 1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Queries computed styles out of a specially-parsed CSS stylesheet.
-- See in particular `QueryableStyleSheet`, `queryRules`, & `cascade'`.
module Data.CSS.Style(
        QueryableStyleSheet, QueryableStyleSheet'(..), queryableStyleSheet,
        queryRules,

M src/Data/CSS/Style/Cascade.hs => src/Data/CSS/Style/Cascade.hs +6 -0
@@ 1,4 1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Applies CSS selection, cascade, & inheritance.
-- INTERNAL MODULE.
module Data.CSS.Style.Cascade(
        query, cascade,
        TrivialPropertyParser(..), PropertyParser(..), Props


@@ 41,12 43,14 @@ instance PropertyParser TrivialPropertyParser where
    longhand _ (TrivialPropertyParser self) key value =
        Just $ TrivialPropertyParser $ insert (unpack key) value self

-- | "key: value;" entries to be parsed into an output type.
type Props = [(Text, [Token])]

--------
---- Query/Psuedo-elements
--------

-- | Looks up style rules for an element, grouped by psuedoelement.
query :: RuleStore s => s -> Element -> HashMap Text [StyleRule']
query self el = Prelude.foldr yield empty $ lookupRules self el
    where yield rule store = insertWith (++) (psuedoElement rule) [resolveAttr rule el] store


@@ 55,6 59,8 @@ query self el = Prelude.foldr yield empty $ lookupRules self el
---- Cascade/Inheritance
--------

-- | Applies cascade for the given `StyleRule'`s & explicit styles,
-- parsed to a value of the same `PropertyParser` type passed in & inheriting from it.
cascade :: PropertyParser p => [StyleRule'] -> Props -> p -> p
cascade styles overrides base =
    construct base $ toList $ cascadeRules (getVars base ++ overrides) styles

M src/Data/CSS/Style/Common.hs => src/Data/CSS/Style/Common.hs +9 -1
@@ 1,3 1,5 @@
-- | Central infrastructure for implementing queryable stylesheets.
-- NOTE: This internal module isn't intended to be fully documented.
module Data.CSS.Style.Common(
        RuleStore(..), StyleRule'(..), selector, properties, psuedoElement, styleRule',
        Element(..), Attribute(..),


@@ 10,12 12,18 @@ import Data.CSS.Syntax.Selector
import Data.CSS.Syntax.Tokens
import Data.Text.Internal (Text(..))

-- | An inversely-linked tree of elements, to apply CSS selectors to.
data Element = ElementNode {
    -- | The element's parent in the tree.
    parent :: Maybe Element,
    -- | The element's previous sibling in the tree.
    previous :: Maybe Element,
    -- | The element's name.
    name :: Text,
    attributes :: [Attribute] -- in sorted order.
    -- | The element's attributes, in sorted order.
    attributes :: [Attribute]
}
-- | A key-value attribute.
data Attribute = Attribute Text String deriving (Eq, Ord)

class RuleStore a where

M src/Data/CSS/Style/Importance.hs => src/Data/CSS/Style/Importance.hs +3 -0
@@ 1,4 1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Evaluates !important.
-- INTERNAL MODULE.
module Data.CSS.Style.Importance (
        ImportanceSplitter(..)
    ) where


@@ 18,6 20,7 @@ splitProperties [] = ([], [])
--- NOTE: Prorities are defined with lower numbers being more important,
---     so negate to be consistant with other priority sources.
--- This API decision started out being accidental, but I find it more intuitive.
-- | Evaluates "!important" by splitting all `StyleRule'` in two.
data ImportanceSplitter a = ImportanceSplitter a
instance RuleStore inner => RuleStore (ImportanceSplitter inner) where
    new = ImportanceSplitter new

M src/Data/CSS/Style/Selector/Index.hs => src/Data/CSS/Style/Selector/Index.hs +4 -0
@@ 1,4 1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Fast lookup & storage for style rules.
-- INTERNAL MODULE.
module Data.CSS.Style.Selector.Index (
        StyleIndex(..),
        rulesForElement


@@ 13,6 15,7 @@ import Data.Hashable
import Data.Text (unpack, pack)
import Data.CSS.Syntax.Tokens (serialize) -- for easy hashing

-- | Fast lookup & storage for style rules.
data StyleIndex = StyleIndex {
    indexed :: HashMap SimpleSelector [StyleRule'],
    unindexed :: [StyleRule']


@@ 31,6 34,7 @@ instance RuleStore StyleIndex where
            index = indexed self
            rules = unindexed self : Prelude.map get (testsForElement element)

-- | LEGACY TESTING API.
rulesForElement :: StyleIndex -> Element -> [StyleRule] -- For testing
rulesForElement self element = Prelude.map inner $ lookupRules self element


M src/Data/CSS/Style/Selector/Interpret.hs => src/Data/CSS/Style/Selector/Interpret.hs +5 -0
@@ 1,4 1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Evaluates CSS selectors over an element.
-- INTERNAL MODULE.
module Data.CSS.Style.Selector.Interpret(
        compile, SelectorFunc,
        InterpretedRuleStore(..)


@@ 10,9 12,11 @@ import Data.Text (unpack)
import Data.List
import Data.Maybe

-- | A compiled(?) CSS selector.
type SelectorFunc = Element -> Bool
type AttrsFunc = [Attribute] -> Bool

-- | Converts a parsed CSS selector into a callable function.
compile :: Selector -> SelectorFunc
compile (Element sel) = compileInner sel
compile (Child upSel sel) = direct parent (compile upSel) $ compileInner sel


@@ 88,6 92,7 @@ hasLang expected value = expected == value || isPrefixOf (expected ++ "-") value
--------
---- RuleStore wrapper
--------
-- | Compiles & fully evaluates CSS selectors.
data InterpretedRuleStore inner = InterpretedRuleStore inner
instance RuleStore inner => RuleStore (InterpretedRuleStore inner) where
    new = InterpretedRuleStore new

M src/Data/CSS/Style/Selector/Specificity.hs => src/Data/CSS/Style/Selector/Specificity.hs +3 -0
@@ 1,4 1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Sorts `StyleRule'`s by specificity.
-- INTERNAL MODULE.
module Data.CSS.Style.Selector.Specificity(
        OrderedRuleStore(..)
    ) where


@@ 27,6 29,7 @@ computeSpecificity' [] = (0, 0, 0)
add :: Vec -> Vec -> Vec
add (a, b, c) (x, y, z) = (a + x, b + y, c + z)

-- | Sorts `StyleRule'`s by their selector specificity.
data OrderedRuleStore inner = OrderedRuleStore inner Int

instance RuleStore inner => RuleStore (OrderedRuleStore inner) where

M src/Data/CSS/Syntax/Selector.hs => src/Data/CSS/Syntax/Selector.hs +23 -8
@@ 1,3 1,5 @@
-- | Parses CSS selectors
-- See `parseSelectors`
module Data.CSS.Syntax.Selector(
        Selector(..), SimpleSelector(..), PropertyTest(..),
        parseSelectors


@@ 8,18 10,31 @@ import Data.CSS.Syntax.StylishUtil

import Data.Text.Internal (Text(..))

-- type Selector = [SimpleSelector]
data Selector = Element [SimpleSelector] |
    Child Selector [SimpleSelector] | Descendant Selector [SimpleSelector] |
    Adjacent Selector [SimpleSelector] | Sibling Selector [SimpleSelector]
-- | A CSS "selector" indicating which elements should be effected by CSS.
data Selector = Element [SimpleSelector] -- ^ Selects a single element.
    | Child Selector [SimpleSelector] -- ^ Represents "a > b" operator.
    | Descendant Selector [SimpleSelector] -- ^ Represents "a b" operator.
    | Adjacent Selector [SimpleSelector] -- ^ Represents "a + b" operator.
    | Sibling Selector [SimpleSelector] -- ^ Represents "a ~ b" operator.
    deriving (Show, Eq)
data SimpleSelector = Tag Text | Id Text | Class Text | Property Text PropertyTest |
    Psuedoclass Text [Token]
-- | An individual test comprising a CSS stylesheet.
data SimpleSelector = Tag Text -- ^ Matches a tagname, e.g. "a"
    | Id Text -- ^ Matches the "id" attribute, e.g. "#header"
    | Class Text -- ^ Matches the "class" attribute, e.g. ".ad"
    | Property Text PropertyTest -- ^ Matches a specified property
    | Psuedoclass Text [Token] -- ^ Matches psuedoclasses provided by the caller (via a nameless property).
    deriving (Show, Eq)
data PropertyTest = Exists | Equals Text | Suffix Text | Prefix Text | Substring Text |
    Include Text | Dash Text
-- | How should a property be matched.
data PropertyTest = Exists -- ^ Matches whether an attribute actually exists, e.g. "[title]"
    | Equals Text -- ^ Matches whether the attribute is exactly equal to the value, e.g. "="
    | Suffix Text -- ^ Matches whether attribute ends with the given value, e.g. "$="
    | Prefix Text -- ^ Matches whether attribute starts with the given value, e.g. "^="
    | Substring Text -- ^ Matches whether the attribute contains the given value, e.g. "*="
    | Include Text -- ^ Is one of the whitespace-seperated values the one specified? e.g. "~="
    | Dash Text -- ^ Matches whitespace seperated values, or their "-"-seperated prefixes. e.g. "|="
    deriving (Show, Eq)

-- | Parses a CSS selector.
parseSelectors :: Parser [Selector]
parseSelectors tokens = concatP (:) parseCompound parseSelectorsTail $ skipSpace tokens
parseSelectorsTail :: Parser [Selector]

M src/Data/CSS/Syntax/StyleSheet.hs => src/Data/CSS/Syntax/StyleSheet.hs +19 -0
@@ 1,4 1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Parses a CSS stylesheet
-- See `StyleSheet` & `parseForURL`.
module Data.CSS.Syntax.StyleSheet (
        parse, parse', parseForURL, TrivialStyleSheet(..),
        StyleSheet(..), skipAtRule, scanAtRule, scanBlock, skipSpace,


@@ 20,20 22,28 @@ import Network.URI (parseRelativeReference, relativeTo, uriToString, URI(..))
--------
---- Output type class
--------
-- | Describes how to store, and to some extent parse, CSS stylesheets.
-- These methods are used to construct the results from `parse`, etc.
class StyleSheet s where
    -- | Sets the stylesheet priority (useragent vs user vs author), optional.
    setPriority :: Int -> s -> s
    setPriority _ = id
    -- | Stores a parsed selector+properties rule.
    addRule :: s -> StyleRule -> s
    -- | Stores and parses an identified at-rule.
    addAtRule :: s -> Text -> [Token] -> (s, [Token])
    addAtRule self _ tokens = (self, skipAtRule tokens)

-- | Stores the parsed selector*s*+proeprties rule.
addRules :: StyleSheet ss => ss -> ([Selector], ([(Text, [Token])], Text)) -> ss
addRules self (selector:selectors, val@(props, psuedoel)) = addRules self' (selectors, val)
    where self' = addRule self $ StyleRule selector props psuedoel
addRules self ([], _) = self

-- | The properties to set for elements matching the given selector.
data StyleRule = StyleRule Selector [(Text, [Token])] Text deriving (Show, Eq)

-- | Gathers StyleRules into a list, mainly for testing.
data TrivialStyleSheet = TrivialStyleSheet [StyleRule] deriving (Show, Eq)
instance StyleSheet TrivialStyleSheet where
    addRule (TrivialStyleSheet self) rule = TrivialStyleSheet $ rule:self


@@ 41,9 51,11 @@ instance StyleSheet TrivialStyleSheet where
--------
---- Basic parsing
--------
-- | Parse a CSS stylesheet
parse :: StyleSheet s => s -> Text -> s
parse stylesheet source = parse' stylesheet $ tokenize source

-- | Parse a CSS stylesheet, resolving all URLs to absolute form.
parseForURL :: StyleSheet s => s -> URI -> Text -> s
parseForURL stylesheet base source = parse' stylesheet $ rewriteURLs $ tokenize source
    where


@@ 54,6 66,7 @@ parseForURL stylesheet base source = parse' stylesheet $ rewriteURLs $ tokenize 
        rewriteURLs (tok:toks) = tok : rewriteURLs toks
        rewriteURLs [] = []

-- | Parse a tokenized (via `css-syntax`) CSS stylesheet
parse' :: StyleSheet t => t -> [Token] -> t
-- Things to skip.
parse' stylesheet (Whitespace:tokens) = parse' stylesheet tokens


@@ 71,6 84,7 @@ parse' stylesheet tokens = parse' (addRules stylesheet rule) tokens'
--------
---- Property parsing
--------
-- | Parse "{key: value; ...}" property values, with a psuedoelement.
parseProperties :: Parser ([(Text, [Token])], Text)
parseProperties (LeftCurlyBracket:tokens) = noPsuedoel $ parseProperties' tokens
parseProperties (Whitespace:tokens) = parseProperties tokens


@@ 83,6 97,7 @@ parseProperties [] = noPsuedoel ([], [])
noPsuedoel :: (x, y) -> ((x, Text), y)
noPsuedoel (val, tokens) = ((val, ""), tokens)

-- | Parse "key: value;"... property values, as per the HTML "style" property.
parseProperties' :: Parser [(Text, [Token])]
parseProperties' (Whitespace:tokens) = parseProperties' tokens
parseProperties' (Ident name:tokens)


@@ 96,6 111,7 @@ parseProperties' tokens = parseProperties' (skipValue tokens)
--------
---- Skipping/Scanning utilities
--------
-- | Returns tokens before & after an at-rule value, terminated after a curly-bracketed block or a semicolon.
scanAtRule :: Parser [Token]
scanAtRule (Semicolon:tokens) = ([Semicolon], tokens)
scanAtRule tokens@(LeftCurlyBracket:_) = scanInner tokens $ \rest -> ([], rest)


@@ 110,9 126,11 @@ scanAtRule (RightSquareBracket:tokens) = ([], RightSquareBracket:tokens)

scanAtRule tokens = capture scanAtRule tokens

-- | Returns tokens after an at-rule, as per `scanAtRule`.
skipAtRule :: [Token] -> [Token]
skipAtRule tokens = snd $ scanAtRule tokens

-- | Returns tokens before & after a semicolon.
scanValue :: Parser [Token]
scanValue (Semicolon:tokens) = ([], tokens)
scanValue (Whitespace:tokens) = scanValue tokens


@@ 128,5 146,6 @@ scanValue (RightSquareBracket:tokens) = ([], RightSquareBracket:tokens)

scanValue tokens = capture scanValue tokens

-- | Returns tokens after a semicolon.
skipValue :: [Token] -> [Token]
skipValue tokens = snd $ scanValue tokens

D src/Data/CSS/Syntax/StyleSheet/ByteString.hs => src/Data/CSS/Syntax/StyleSheet/ByteString.hs +0 -9
@@ 1,9 0,0 @@
-- To determine the text encoding, attempt each text encoding to look for an initial @charset, falling back to UTF8
-- An abstraction would do the test itself.
-- text (Data.Text.Encoding) module includes:
--  decodeLatin1
--  decodeUtf8
--  decodeUtf16LE
--  decodeUtf16BE
--  decodeUtf32LE
--  decodeUtf32BE

M src/Data/CSS/Syntax/StylishUtil.hs => src/Data/CSS/Syntax/StylishUtil.hs +9 -0
@@ 1,3 1,4 @@
-- | Utility parser combinators for parsing CSS stylesheets.
module Data.CSS.Syntax.StylishUtil(
        concatP, capture, skipSpace,
        scanBlock, skipBlock, scanInner,


@@ 6,22 7,28 @@ module Data.CSS.Syntax.StylishUtil(

import Data.CSS.Syntax.Tokens

-- | A simple parser combinator type.
type Parser x = [Token] -> (x, [Token])

-- | Chains two parser combinators together.
concatP :: (a -> b -> c) -> Parser a -> Parser b -> Parser c
concatP join left right tokens = (join x y, remainder)
    where
        (x, tokens') = left tokens
        (y, remainder) = right tokens'

-- | "captures" the token being parsed into the returned output.
capture :: Parser [Token] -> Parser [Token]
capture cb (token:tokens) = (token:captured, tokens')
   where (captured, tokens') = cb tokens
capture _ [] = ([], [])

-- | Removes preceding `Whitespace` tokens.
skipSpace :: [Token] -> [Token]
skipSpace (Whitespace:tokens) = skipSpace tokens
skipSpace tokens = tokens

-- | Returns tokens until the next unbalanced closing brace.
scanBlock :: Parser [Token]
-- TODO assert closing tags are correct
--    But what should the error recovery be?


@@ 36,9 43,11 @@ scanBlock tokens@(LeftSquareBracket:_) = scanInner tokens scanBlock

scanBlock tokens = capture scanBlock tokens

-- | Returns tokens after the next unbalanced closing brace.
skipBlock :: [Token] -> [Token]
skipBlock tokens = snd $ scanBlock tokens

-- | Parses a block followed by the given combinator, returning the tokens the matched.
scanInner :: [Token] -> Parser [Token] -> ([Token], [Token])
scanInner (token:tokens) cb = concatP gather scanBlock cb tokens
    where gather x y = token : x ++ y

M stylist.cabal => stylist.cabal +2 -2
@@ 10,7 10,7 @@ name:                stylist
-- PVP summary:      +-+------- breaking API changes
--                   | | +----- non-breaking API additions
--                   | | | +--- code changes with no API change
version:             1.1.1.0
version:             1.2.0.0

-- A short (one-line) description of the package.
synopsis:            Apply CSS styles to a document tree.


@@ 84,6 84,6 @@ test-suite test-stylist
  other-modules:        Data.CSS.Syntax.StyleSheet, Data.CSS.Syntax.Selector, Data.CSS.Style
  build-depends:       base >=4.9 && <=4.12, css-syntax >=0.1 && <0.2, text,
                        unordered-containers >= 0.2 && <0.3, hashable,
                        network-uri >= 2.6 && <2.7, hspec, QuickCheck,
                        network-uri >= 2.6 && <2.7, async >= 2.1 && <2.3, hspec, QuickCheck,
                        scientific >= 0.3 && <1.0
  ghc-options: -Wall

M xml-conduit-stylist/src/Data/HTML2CSS.hs => xml-conduit-stylist/src/Data/HTML2CSS.hs +10 -0
@@ 1,4 1,5 @@
{-# LANGUAGE OverloadedStrings #-}
-- | Bindings from `xml-conduit` to `haskell-stylist`.
module Data.HTML2CSS(
        externalStyles, externalStylesForURL, internalStyles, internalStylesForURL, -- legacy
        html2css, cssPriorityAgent, cssPriorityUser, cssPriorityAuthor, -- parsing


@@ 50,9 51,11 @@ parseMediaQuery attrs
    | otherwise = []

---- Parsing (legacy)
-- | LEGACY: Extract relative links to external stylesheets.
externalStyles :: StyleSheet s => s -> (M.Map XML.Name Txt.Text -> Bool) ->
        XML.Element -> (URI -> IO Txt.Text) -> IO s
externalStyles a b c d = externalStylesForURL a b c nullURI d
-- | LEGACY: Extract absolutized links to external stylesheets.
externalStylesForURL stylesheet testMedia html base loadURL = do
    css <- externalStyles' testMedia html base loadURL
    return $ foldl (\a (b, c) -> parseForURL a b c) (cssPriorityAuthor stylesheet) css


@@ 72,7 75,9 @@ linkedStyles' testMedia (XML.Element (XML.Name "link" _ _) attrs _)
linkedStyles' testMedia (XML.Element _ _ children) =
    concat [linkedStyles' testMedia el | XML.NodeElement el <- children]

-- | LEGACY: Extract internally embedded CSS stylesheets.
internalStyles a b c = internalStylesForURL a b nullURI c
-- | LEGACY: Extract internally embedded CSS stylesheets, with absolutized URLs.
internalStylesForURL testMedia stylesheet base html =
    foldl (\s -> parseForURL s base) (cssPriorityAuthor stylesheet) $
        internalStyles' testMedia html


@@ 92,12 97,16 @@ strContent (_:rest) = strContent rest
strContent [] = ""

---- Styling
-- | Converts a parsed XML or HTML document to a specified style tree type.
traverseStyles :: PropertyParser s => (s -> [o] -> o) -> (s -> Txt.Text -> o) ->
        QueryableStyleSheet s -> XML.Element -> o
traverseStyles = traverseStyles' Nothing temp Nothing (\x y -> Nothing)
-- | Converts a parsed XML or HTML document to a specified style tree type,
-- with a routine to compute alternative contents based on the raw element or computed styles.
traversePrepopulatedStyles :: PropertyParser s => (s -> XML.Element -> Maybe [o]) ->
        (s -> [o] -> o) -> (s -> Txt.Text -> o) -> QueryableStyleSheet s -> XML.Element -> o
traversePrepopulatedStyles = traverseStyles' Nothing temp Nothing
-- | Full routine for converting a parsed XML or HTML document to a specified style tree type.
traverseStyles' :: PropertyParser s => Maybe Element -> s -> Maybe Element ->
        (s -> XML.Element -> Maybe [o]) -> (s -> [o] -> o) -> (s -> Txt.Text -> o) ->
        QueryableStyleSheet s -> XML.Element -> o


@@ 128,6 137,7 @@ traversePsuedo rules psuedo parentStyle builder
    | Just rules' <- HM.lookup psuedo rules = [builder (cascade' rules' [] parentStyle) []]
    | otherwise = []

-- | Converts a xml-conduit Element to a stylist Element.
elToStylish (XML.Element (XML.Name name _ _) attrs _) parent previous =
    ElementNode {
        name = name,