~alcinnz/haskell-stylist

2128054b93bb30b8959f4d32b8052d8c41834698 — Adrian Cochrane 5 years ago b15571f
Factorize out cascade logic.
2 files changed, 45 insertions(+), 39 deletions(-)

M src/Data/CSS/Style.hs
A src/Data/CSS/Style/Cascade.hs
M src/Data/CSS/Style.hs => src/Data/CSS/Style.hs +5 -39
@@ 11,13 11,14 @@ import Data.CSS.Style.Selector.Interpret
import Data.CSS.Style.Selector.Specificity
import Data.CSS.Style.Importance
import Data.CSS.Style.Common
import Data.CSS.Syntax.StyleSheet (StyleSheet(..))
import qualified Data.CSS.Style.Cascade as Cascade
import Data.CSS.Style.Cascade (PropertyParser(..), TrivialPropertyParser)

-- TODO do performance tests to decide beside between strict/lazy,
--      or is another Map implementation better?
import Data.HashMap.Strict
import Data.CSS.Syntax.Tokens
import Data.Text (unpack)
import Data.CSS.Syntax.Tokens (Token)
import Data.CSS.Syntax.StyleSheet (StyleSheet(..))

type QueryableStyleSheet parser = QueryableStyleSheet' (ImportanceSplitter (
        PropertyExpander parser (OrderedRuleStore (InterpretedRuleStore StyleIndex))


@@ 43,33 44,8 @@ queryRules (QueryableStyleSheet' store _ _) el = lookupRules store el
---- Cascade
--------

cascadeRules overrides rules = cascadeProperties overrides $ concat $ Prelude.map properties rules

cascadeProperties overrides props = fromList (props ++ overrides)

--------
---- Dispatch to property definitions
--------

class PropertyParser a where
    temp :: a
    inherit :: a -> a
    inherit = id

    shorthand :: a -> Text -> [Token] -> [(Text, [Token])]
    shorthand self name value | Just _ <- longhand self self name value = [(name, value)]
        | otherwise = []
    -- longhand parent self name value
    longhand :: a -> a -> Text -> [Token] -> Maybe a

cascade :: PropertyParser p => QueryableStyleSheet p -> Element -> [(Text, [Token])] -> p -> p
cascade self el overrides parent = dispatch parent (inherit parent) $
    toList $ cascadeRules overrides $ queryRules self el

dispatch parent child ((name, value):props)
    | Just child' <- longhand parent child name value = dispatch parent child' props
    | otherwise = dispatch parent child props
dispatch _ child [] = child
cascade (QueryableStyleSheet' store _ _) = Cascade.cascade store

--- Verify syntax during parsing, so invalid properties don't interfere with cascade.
data PropertyExpander parser inner = PropertyExpander parser inner


@@ 84,13 60,3 @@ expandRule parser rule = rule {inner = StyleRule selector $ expandProperties par
expandProperties parser ((name, value):props) =
        shorthand parser name value ++ expandProperties parser props
expandProperties _ [] = []

--------
---- Testing utility
--------

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

A src/Data/CSS/Style/Cascade.hs => src/Data/CSS/Style/Cascade.hs +40 -0
@@ 0,0 1,40 @@
module Data.CSS.Style.Cascade(
        cascade, TrivialPropertyParser(..), PropertyParser(..)
    ) where

import Data.CSS.Style.Common
import Data.CSS.Syntax.Tokens

-- TODO do performance tests to decide beside between strict/lazy,
--      or is another Map implementation better?
import Data.HashMap.Strict
import Data.Text (unpack)

cascadeRules overrides rules = cascadeProperties overrides $ concat $ Prelude.map properties rules
cascadeProperties overrides props = fromList (props ++ overrides)

class PropertyParser a where
    temp :: a
    inherit :: a -> a
    inherit = id

    shorthand :: a -> Text -> [Token] -> [(Text, [Token])]
    shorthand self name value | Just _ <- longhand self self name value = [(name, value)]
        | otherwise = []
    -- longhand parent self name value
    longhand :: a -> a -> Text -> [Token] -> Maybe a

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

cascade :: (PropertyParser p, RuleStore s) => s -> Element -> [(Text, [Token])] -> p -> p
cascade self el overrides parent = dispatch parent (inherit parent) $
    toList $ cascadeRules overrides $ lookupRules self el

dispatch parent child ((name, value):props)
    | Just child' <- longhand parent child name value = dispatch parent child' props
    | otherwise = dispatch parent child props
dispatch _ child [] = child