packages feed

stylist 1.1.1.0 → 1.2.0.0

raw patch · 13 files changed

+159/−26 lines, 13 filesdep +async

Dependencies added: async

Files

src/Data/CSS/Preprocessor/Conditions.hs view
@@ -1,7 +1,11 @@ {-# 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,+        extractImports, resolveImports, loadImports, resolve, testIsStyled,         Datum(..)     ) where @@ -16,19 +20,29 @@ import Data.Text.Internal (Text(..)) import Data.Text (unpack) import Network.URI (URI(..), URIAuth(..), parseURI)+import Control.Concurrent.Async (forConcurrently)  import Data.List +-- | Collects and evaluates conditional at-rules. data ConditionalStyles p = ConditionalStyles {+    -- | The URL to the webpage being styled, for `@document` rules.     hostURL :: URI,+    -- | The type of document, `@document domain(...)` rules.     mediaDocument :: String,+    -- | Whether the page provided any of it's own styling (valid or not)+    isUnstyled :: Bool,+    -- | Queued style rules, to be evaluated later.     rules :: [ConditionalRule p],+    -- | PropertyParser to test against for `@supports` rules.     propertyParser :: p } +-- | Constructs an empty `ConditionalStyles`. conditionalStyles :: PropertyParser p => URI -> String -> ConditionalStyles p-conditionalStyles uri mediaDocument' = ConditionalStyles uri mediaDocument' [] temp+conditionalStyles uri mediaDocument' = ConditionalStyles uri mediaDocument' False [] temp +-- | Style rules that can be queued in a `ConditionalStyles`. data ConditionalRule p = Priority Int | StyleRule' StyleRule | AtRule Text [Token] |     External Query.Expr URI | Internal Query.Expr (ConditionalStyles p) @@ -66,6 +80,10 @@     addAtRule self "document" (Function "media-document":String match:RightParen:toks)         | unpack match == mediaDocument self = parseAtBlock self toks         | otherwise = addAtRule self "document" toks+    -- Rhapsode-specific: matches if the document didn't provide any of it's own stylings.+    addAtRule self "document" (Ident "unstyled":toks)+        | isUnstyled self = parseAtBlock self toks+        | otherwise = addAtRule self "document" toks     -- TODO Support regexp() conditions, requires new dependency     addAtRule self "document" tokens = (self, skipAtRule tokens) @@ -87,6 +105,12 @@      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 }+ -------- ---- @import/@media --------@@ -97,10 +121,12 @@         (addRule' self $ External cond uri, toks') parseAtImport self _ toks = (self, skipAtRule toks) +-- | Returns `@import` URLs that need to be imported. extractImports :: (Text -> Query.Datum) -> (Token -> Query.Datum) -> ConditionalStyles p -> [URI] extractImports vars evalToken self =     [uri | External cond uri <- rules self, Query.eval vars evalToken cond] +-- | Substitutes external values in for `@import` rules. resolveImports :: ConditionalStyles p -> [(URI, ConditionalStyles p)] -> ConditionalStyles p resolveImports self responses = self {rules = map resolveImport $ rules self}     where@@ -108,22 +134,20 @@             Internal cond body         resolveImport x = x +-- | Evaluates a given "loader" to resolve any `@import` rules. loadImports :: PropertyParser p => (URI -> IO Text) -> (Text -> Query.Datum) -> (Token -> Query.Datum) ->         ConditionalStyles p -> [URI] -> IO (ConditionalStyles p) loadImports loader vars evalToken self blocklist = do         let imports = extractImports vars evalToken self-        imported <- loadAll [url | url <- imports, url `notElem` blocklist] Nothing-        return $ resolveImports self imported-    where-        loadAll urls Nothing = loadAll urls $ Just urls-        loadAll (url:urls) (Just blocklist') = do+        let urls = [url | url <- imports, url `notElem` blocklist]+        imported <- forConcurrently urls $ \url -> do             source <- loader url             let parsed = parse self {rules = []} source-            styles <- loadImports loader vars evalToken parsed (blocklist ++ blocklist')-            rest <- loadAll urls $ Just blocklist'-            return ((url, styles):rest)-        loadAll [] _ = return []+            styles <- loadImports loader vars evalToken parsed (blocklist ++ urls)+            return (url, styles)+        return $ resolveImports self imported +-- | Evaluates any media queries, returning a new StyleSheet with the queued operations. resolve :: StyleSheet s => (Text -> Query.Datum) -> (Token -> Query.Datum) ->         s -> ConditionalStyles p -> s resolve v t styles self = resolve' v t (reverse $ rules self) styles
src/Data/CSS/Preprocessor/Conditions/Expr.hs view
@@ -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.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 @@ -55,8 +71,10 @@ -------- ---- Shunting Yard Evaluator --------+-- | 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' [] 
src/Data/CSS/Style.hs view
@@ -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,@@ -21,16 +23,22 @@ import Data.Text (isPrefixOf) import Data.List (elemIndex) +-- | A parsed CSS stylesheet from which you can query styles to match an element. type QueryableStyleSheet parser = QueryableStyleSheet' (ImportanceSplitter (         PropertyExpander parser (OrderedRuleStore (InterpretedRuleStore StyleIndex))     )) parser +-- | More generic version of `QueryableStyleSheet`. data QueryableStyleSheet' store parser = QueryableStyleSheet' {+    -- | Internal datastructure for efficient style lookup.     store :: store,+    -- | The "PropertyParser" to use for property syntax validation.     parser :: parser,+    -- | Whether author, useragent, or user styles are currently being parsed.     priority :: Int -- author vs user agent vs user styles } +-- | Constructs an empty QueryableStyleSheet'. queryableStyleSheet :: PropertyParser p => QueryableStyleSheet p queryableStyleSheet = QueryableStyleSheet' {store = new, parser = temp, priority = 0} @@ -41,14 +49,17 @@         }  --- Reexpose cascade methods+-- | Looks up style rules matching the specified element, grouped by psuedoelement. queryRules :: (PropertyParser p, RuleStore s) =>     QueryableStyleSheet' s p -> Element -> HashMap Text [StyleRule'] queryRules (QueryableStyleSheet' store' _ _) = Cascade.query store' +-- | Selects used property values from the given style rules,+-- & populates into a new `PropertyParser` inheriting from the one given. cascade' :: PropertyParser p => [StyleRule'] -> Props -> p -> p cascade' = Cascade.cascade ---- Facade for trivial cases+-- | Facade over `queryRules` & `cascade'` for simple cases you don't care about psuedoelements. cascade :: PropertyParser p => QueryableStyleSheet p -> Element -> Props -> p -> p cascade self el = cascade' $ lookupDefault [] "" $ queryRules self el @@ -71,6 +82,7 @@ -------- ---- var() --------+-- | `PropertyParser` that lowers var() calls before forwarding to another. data VarParser a = VarParser {vars :: Props, innerParser :: a}  instance PropertyParser p => PropertyParser (VarParser p) where
src/Data/CSS/Style/Cascade.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE OverloadedStrings #-}+-- | Applies CSS selection, cascade, & inheritance.+-- INTERNAL MODULE. module Data.CSS.Style.Cascade(         query, cascade,         TrivialPropertyParser(..), PropertyParser(..), Props@@ -12,34 +14,43 @@ import Data.HashMap.Strict import Data.Text (unpack, pack, isPrefixOf) +-- | Defines how to parse CSS properties into an output "style" format. class PropertyParser a where+    -- | Default styles.     temp :: a+    -- | Creates a style inherited from a parent style.     inherit :: a -> a     inherit = id +    -- | Expand a shorthand property into longhand properties.     shorthand :: a -> Text -> [Token] -> [(Text, [Token])]     shorthand self key value | Just _ <- longhand self self key value = [(key, value)]         | otherwise = []     -- longhand parent self name value     longhand :: a -> a -> Text -> [Token] -> Maybe a +    -- | Retrieve stored variables, optional.     getVars :: a -> Props     getVars _ = []+    -- | Save variable values, optional.     setVars :: Props -> a -> a     setVars _ = id +-- | Gather properties into a hashmap. data TrivialPropertyParser = TrivialPropertyParser (HashMap String [Token]) instance PropertyParser TrivialPropertyParser where     temp = TrivialPropertyParser empty     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@@ -48,6 +59,8 @@ ---- 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
src/Data/CSS/Style/Common.hs view
@@ -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.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
src/Data/CSS/Style/Importance.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE OverloadedStrings #-}+-- | Evaluates !important.+-- INTERNAL MODULE. module Data.CSS.Style.Importance (         ImportanceSplitter(..)     ) where@@ -18,6 +20,7 @@ --- 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
src/Data/CSS/Style/Selector/Index.hs view
@@ -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.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 @@             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 
src/Data/CSS/Style/Selector/Interpret.hs view
@@ -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.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 @@ -------- ---- RuleStore wrapper --------+-- | Compiles & fully evaluates CSS selectors. data InterpretedRuleStore inner = InterpretedRuleStore inner instance RuleStore inner => RuleStore (InterpretedRuleStore inner) where     new = InterpretedRuleStore new
src/Data/CSS/Style/Selector/Specificity.hs view
@@ -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 @@ 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
src/Data/CSS/Syntax/Selector.hs view
@@ -1,3 +1,5 @@+-- | Parses CSS selectors+-- See `parseSelectors` module Data.CSS.Syntax.Selector(         Selector(..), SimpleSelector(..), PropertyTest(..),         parseSelectors@@ -8,18 +10,31 @@  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]
src/Data/CSS/Syntax/StyleSheet.hs view
@@ -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 @@ -------- ---- 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 @@ -------- ---- 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 @@         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 @@ -------- ---- 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 @@ 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 @@ -------- ---- 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 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 tokens = capture scanValue tokens +-- | Returns tokens after a semicolon. skipValue :: [Token] -> [Token] skipValue tokens = snd $ scanValue tokens
src/Data/CSS/Syntax/StylishUtil.hs view
@@ -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 @@  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 = 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
stylist.cabal view
@@ -10,7 +10,7 @@ -- 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.@@ -66,7 +66,7 @@   -- Other library packages from which modules are imported.   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+                        network-uri >= 2.6 && <2.7, async >= 2.1 && <2.3      -- Directories containing source files.   hs-source-dirs:      src@@ -84,6 +84,6 @@   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