{-# OPTIONS_HADDOCK hide #-}
-- | This module is only being exposed to work around a GHC bug, its API is not stable

{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveLift #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE EmptyDataDecls #-}
module Text.Internal.Css where

import Data.List (intersperse, intercalate)
import Data.Text.Lazy.Builder (Builder, singleton, toLazyText, fromLazyText, fromString)
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TLB
import Data.Monoid (Monoid, mconcat, mappend, mempty)
import Data.Semigroup (Semigroup(..))
import Data.Text (Text)
import qualified Data.Text as T
import Language.Haskell.TH.Syntax
import System.IO.Unsafe (unsafePerformIO)
import Text.ParserCombinators.Parsec (Parser, parse)
import Text.Shakespeare.Base hiding (Scope)
import Language.Haskell.TH
import Control.Applicative ((<$>), (<*>))
import Control.Arrow ((***), second)
import Text.IndentToBrace (i2b)
import Data.Functor.Identity (runIdentity)
import Text.Shakespeare (VarType (..))

type CssUrl url = (url -> [(T.Text, T.Text)] -> T.Text) -> Css

type DList a = [a] -> [a]

data Resolved = Resolved | Unresolved

-- Should mixins keep order (new version) or not (deprecated version)
data Order = Ordered | Unordered deriving (Order -> Q Exp
Order -> Q (TExp Order)
(Order -> Q Exp) -> (Order -> Q (TExp Order)) -> Lift Order
forall t. (t -> Q Exp) -> (t -> Q (TExp t)) -> Lift t
liftTyped :: Order -> Q (TExp Order)
$cliftTyped :: Order -> Q (TExp Order)
lift :: Order -> Q Exp
$clift :: Order -> Q Exp
Lift)

type HasLeadingSpace = Bool

type family Str (a :: Resolved)
type instance Str 'Resolved = Builder
type instance Str 'Unresolved = Contents

data Block (a :: Resolved) where
  BlockResolved :: 
    { Block 'Resolved -> Builder
brSelectors :: !Builder
    , Block 'Resolved -> [Attr 'Resolved]
brAttrs     :: ![Attr 'Resolved]
    } -> Block 'Resolved
  BlockUnresolved ::
    { Block 'Unresolved -> [Contents]
buSelectors      :: ![Contents]
    , Block 'Unresolved -> [Either (Attr 'Unresolved) Deref]
buAttrsAndMixins :: ![Either (Attr 'Unresolved) Deref]
    , Block 'Unresolved -> [(HasLeadingSpace, Block 'Unresolved)]
buBlocks         :: ![(HasLeadingSpace, Block 'Unresolved)]
    } -> Block 'Unresolved

data Mixin = Mixin
    { Mixin -> [Attr 'Resolved]
mixinAttrs :: ![Attr 'Resolved]
    , Mixin -> [(HasLeadingSpace, Block 'Resolved)]
mixinBlocks :: ![(HasLeadingSpace, Block 'Resolved)]
    }
    deriving Mixin -> Q Exp
Mixin -> Q (TExp Mixin)
(Mixin -> Q Exp) -> (Mixin -> Q (TExp Mixin)) -> Lift Mixin
forall t. (t -> Q Exp) -> (t -> Q (TExp t)) -> Lift t
liftTyped :: Mixin -> Q (TExp Mixin)
$cliftTyped :: Mixin -> Q (TExp Mixin)
lift :: Mixin -> Q Exp
$clift :: Mixin -> Q Exp
Lift
instance Semigroup Mixin where
    Mixin [Attr 'Resolved]
a [(HasLeadingSpace, Block 'Resolved)]
x <> :: Mixin -> Mixin -> Mixin
<> Mixin [Attr 'Resolved]
b [(HasLeadingSpace, Block 'Resolved)]
y = [Attr 'Resolved] -> [(HasLeadingSpace, Block 'Resolved)] -> Mixin
Mixin ([Attr 'Resolved]
a [Attr 'Resolved] -> [Attr 'Resolved] -> [Attr 'Resolved]
forall a. [a] -> [a] -> [a]
++ [Attr 'Resolved]
b) ([(HasLeadingSpace, Block 'Resolved)]
x [(HasLeadingSpace, Block 'Resolved)]
-> [(HasLeadingSpace, Block 'Resolved)]
-> [(HasLeadingSpace, Block 'Resolved)]
forall a. [a] -> [a] -> [a]
++ [(HasLeadingSpace, Block 'Resolved)]
y)
instance Monoid Mixin where
    mempty :: Mixin
mempty = [Attr 'Resolved] -> [(HasLeadingSpace, Block 'Resolved)] -> Mixin
Mixin [Attr 'Resolved]
forall a. Monoid a => a
mempty [(HasLeadingSpace, Block 'Resolved)]
forall a. Monoid a => a
mempty

data TopLevel (a :: Resolved) where
    TopBlock   :: !(Block a) -> TopLevel a
    TopAtBlock :: !String -- name e.g., media
               -> !(Str a) -- selector
               -> ![Block a]
               -> TopLevel a
    TopAtDecl  :: !String -> !(Str a) -> TopLevel a
    TopVar     :: !String -> !String -> TopLevel 'Unresolved

data Attr (a :: Resolved) where
  AttrResolved ::
    { Attr 'Resolved -> Builder
attrResKey :: !Builder
    , Attr 'Resolved -> Builder
attrResVal :: !Builder
    } -> Attr 'Resolved
  AttrUnresolved ::
    { Attr 'Unresolved -> Contents
attrUnresKey :: !Contents
    , Attr 'Unresolved -> Contents
attrUnresVal :: !Contents
    } -> Attr 'Unresolved

data Css = CssWhitespace ![TopLevel 'Resolved]
         | CssNoWhitespace ![TopLevel 'Resolved]

data Content = ContentRaw String
             | ContentVar Deref
             | ContentUrl Deref
             | ContentUrlParam Deref
             | ContentMixin Deref
    deriving (Int -> Content -> ShowS
Contents -> ShowS
Content -> String
(Int -> Content -> ShowS)
-> (Content -> String) -> (Contents -> ShowS) -> Show Content
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: Contents -> ShowS
$cshowList :: Contents -> ShowS
show :: Content -> String
$cshow :: Content -> String
showsPrec :: Int -> Content -> ShowS
$cshowsPrec :: Int -> Content -> ShowS
Show, Content -> Content -> HasLeadingSpace
(Content -> Content -> HasLeadingSpace)
-> (Content -> Content -> HasLeadingSpace) -> Eq Content
forall a.
(a -> a -> HasLeadingSpace) -> (a -> a -> HasLeadingSpace) -> Eq a
/= :: Content -> Content -> HasLeadingSpace
$c/= :: Content -> Content -> HasLeadingSpace
== :: Content -> Content -> HasLeadingSpace
$c== :: Content -> Content -> HasLeadingSpace
Eq, Content -> Q Exp
Content -> Q (TExp Content)
(Content -> Q Exp) -> (Content -> Q (TExp Content)) -> Lift Content
forall t. (t -> Q Exp) -> (t -> Q (TExp t)) -> Lift t
liftTyped :: Content -> Q (TExp Content)
$cliftTyped :: Content -> Q (TExp Content)
lift :: Content -> Q Exp
$clift :: Content -> Q Exp
Lift)

type Contents = [Content]

data CDData url = CDPlain Builder
                | CDUrl url
                | CDUrlParam (url, [(Text, Text)])
                | CDMixin Mixin

pack :: String -> Text
pack :: String -> Text
pack = String -> Text
T.pack

fromText :: Text -> Builder
fromText :: Text -> Builder
fromText = Text -> Builder
TLB.fromText
{-# NOINLINE fromText #-}

class ToCss a where
    toCss :: a -> Builder

instance ToCss [Char] where toCss :: String -> Builder
toCss = Text -> Builder
fromLazyText (Text -> Builder) -> (String -> Text) -> String -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
TL.pack
instance ToCss Text where toCss :: Text -> Builder
toCss = Text -> Builder
fromText
instance ToCss TL.Text where toCss :: Text -> Builder
toCss = Text -> Builder
fromLazyText

-- | Determine which identifiers are used by the given template, useful for
-- creating systems like yesod devel.
cssUsedIdentifiers :: Bool -- ^ perform the indent-to-brace conversion
                   -> Parser [TopLevel 'Unresolved]
                   -> String
                   -> [(Deref, VarType)]
cssUsedIdentifiers :: HasLeadingSpace
-> Parser [TopLevel 'Unresolved] -> String -> [(Deref, VarType)]
cssUsedIdentifiers HasLeadingSpace
toi2b Parser [TopLevel 'Unresolved]
parseBlocks String
s' =
    [[(Deref, VarType)]] -> [(Deref, VarType)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[(Deref, VarType)]] -> [(Deref, VarType)])
-> [[(Deref, VarType)]] -> [(Deref, VarType)]
forall a b. (a -> b) -> a -> b
$ (String -> [[(Deref, VarType)]])
-> ([[(Deref, VarType)]] -> [[(Deref, VarType)]])
-> Either String [[(Deref, VarType)]]
-> [[(Deref, VarType)]]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> [[(Deref, VarType)]]
forall a. HasCallStack => String -> a
error [[(Deref, VarType)]] -> [[(Deref, VarType)]]
forall a. a -> a
id (Either String [[(Deref, VarType)]] -> [[(Deref, VarType)]])
-> Either String [[(Deref, VarType)]] -> [[(Deref, VarType)]]
forall a b. (a -> b) -> a -> b
$ (Content -> Either String [(Deref, VarType)])
-> Contents -> Either String [[(Deref, VarType)]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ([(String, String)] -> Content -> Either String [(Deref, VarType)]
getVars [(String, String)]
scope0) Contents
contents
  where
    s :: String
s = if HasLeadingSpace
toi2b then ShowS
i2b String
s' else String
s'
    a :: [TopLevel 'Unresolved]
a = (ParseError -> [TopLevel 'Unresolved])
-> ([TopLevel 'Unresolved] -> [TopLevel 'Unresolved])
-> Either ParseError [TopLevel 'Unresolved]
-> [TopLevel 'Unresolved]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> [TopLevel 'Unresolved]
forall a. HasCallStack => String -> a
error (String -> [TopLevel 'Unresolved])
-> (ParseError -> String) -> ParseError -> [TopLevel 'Unresolved]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseError -> String
forall a. Show a => a -> String
show) [TopLevel 'Unresolved] -> [TopLevel 'Unresolved]
forall a. a -> a
id (Either ParseError [TopLevel 'Unresolved]
 -> [TopLevel 'Unresolved])
-> Either ParseError [TopLevel 'Unresolved]
-> [TopLevel 'Unresolved]
forall a b. (a -> b) -> a -> b
$ Parser [TopLevel 'Unresolved]
-> String -> String -> Either ParseError [TopLevel 'Unresolved]
forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
parse Parser [TopLevel 'Unresolved]
parseBlocks String
s String
s
    ([(String, String)]
scope0, Contents
contents) = [TopLevel 'Unresolved] -> ([(String, String)], Contents)
go [TopLevel 'Unresolved]
a

    go :: [TopLevel 'Unresolved] -> (Scope, [Content])
    go :: [TopLevel 'Unresolved] -> ([(String, String)], Contents)
go [] = ([], [])
    go (TopAtDecl String
dec Str 'Unresolved
cs:[TopLevel 'Unresolved]
rest) =
        ([(String, String)]
scope, Contents
rest'')
      where
        ([(String, String)]
scope, Contents
rest') = [TopLevel 'Unresolved] -> ([(String, String)], Contents)
go [TopLevel 'Unresolved]
rest
        rest'' :: Contents
rest'' =
            String -> Content
ContentRaw (Char
'@' Char -> ShowS
forall a. a -> [a] -> [a]
: String
dec String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" ")
          Content -> Contents -> Contents
forall a. a -> [a] -> [a]
: Contents
Str 'Unresolved
cs
         Contents -> Contents -> Contents
forall a. [a] -> [a] -> [a]
++ String -> Content
ContentRaw String
";"
          Content -> Contents -> Contents
forall a. a -> [a] -> [a]
: Contents
rest'
    go (TopAtBlock String
_ Str 'Unresolved
_ [Block 'Unresolved]
blocks:[TopLevel 'Unresolved]
rest) =
        ([(String, String)]
scope1 [(String, String)] -> [(String, String)] -> [(String, String)]
forall a. [a] -> [a] -> [a]
++ [(String, String)]
scope2, Contents
rest1 Contents -> Contents -> Contents
forall a. [a] -> [a] -> [a]
++ Contents
rest2)
      where
        ([(String, String)]
scope1, Contents
rest1) = [TopLevel 'Unresolved] -> ([(String, String)], Contents)
go ((Block 'Unresolved -> TopLevel 'Unresolved)
-> [Block 'Unresolved] -> [TopLevel 'Unresolved]
forall a b. (a -> b) -> [a] -> [b]
map Block 'Unresolved -> TopLevel 'Unresolved
forall (a :: Resolved). Block a -> TopLevel a
TopBlock [Block 'Unresolved]
blocks)
        ([(String, String)]
scope2, Contents
rest2) = [TopLevel 'Unresolved] -> ([(String, String)], Contents)
go [TopLevel 'Unresolved]
rest
    go (TopBlock (BlockUnresolved [Contents]
x [Either (Attr 'Unresolved) Deref]
y [(HasLeadingSpace, Block 'Unresolved)]
z):[TopLevel 'Unresolved]
rest) =
        ([(String, String)]
scope1 [(String, String)] -> [(String, String)] -> [(String, String)]
forall a. [a] -> [a] -> [a]
++ [(String, String)]
scope2, Contents
rest0 Contents -> Contents -> Contents
forall a. [a] -> [a] -> [a]
++ Contents
rest1 Contents -> Contents -> Contents
forall a. [a] -> [a] -> [a]
++ Contents
rest2)
      where
        rest0 :: Contents
rest0 = Contents -> [Contents] -> Contents
forall a. [a] -> [[a]] -> [a]
intercalate [String -> Content
ContentRaw String
","] [Contents]
x Contents -> Contents -> Contents
forall a. [a] -> [a] -> [a]
++ (Either (Attr 'Unresolved) Deref -> Contents)
-> [Either (Attr 'Unresolved) Deref] -> Contents
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Either (Attr 'Unresolved) Deref -> Contents
go' [Either (Attr 'Unresolved) Deref]
y
        ([(String, String)]
scope1, Contents
rest1) = [TopLevel 'Unresolved] -> ([(String, String)], Contents)
go (((HasLeadingSpace, Block 'Unresolved) -> TopLevel 'Unresolved)
-> [(HasLeadingSpace, Block 'Unresolved)] -> [TopLevel 'Unresolved]
forall a b. (a -> b) -> [a] -> [b]
map (Block 'Unresolved -> TopLevel 'Unresolved
forall (a :: Resolved). Block a -> TopLevel a
TopBlock (Block 'Unresolved -> TopLevel 'Unresolved)
-> ((HasLeadingSpace, Block 'Unresolved) -> Block 'Unresolved)
-> (HasLeadingSpace, Block 'Unresolved)
-> TopLevel 'Unresolved
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HasLeadingSpace, Block 'Unresolved) -> Block 'Unresolved
forall a b. (a, b) -> b
snd) [(HasLeadingSpace, Block 'Unresolved)]
z)
        ([(String, String)]
scope2, Contents
rest2) = [TopLevel 'Unresolved] -> ([(String, String)], Contents)
go [TopLevel 'Unresolved]
rest
    go (TopVar String
k String
v:[TopLevel 'Unresolved]
rest) =
        ((String
k, String
v)(String, String) -> [(String, String)] -> [(String, String)]
forall a. a -> [a] -> [a]
:[(String, String)]
scope, Contents
rest')
      where
        ([(String, String)]
scope, Contents
rest') = [TopLevel 'Unresolved] -> ([(String, String)], Contents)
go [TopLevel 'Unresolved]
rest
    go' :: Either (Attr 'Unresolved) Deref -> [Content]
    go' :: Either (Attr 'Unresolved) Deref -> Contents
go' (Left (AttrUnresolved Contents
k Contents
v)) = Contents
k Contents -> Contents -> Contents
forall a. [a] -> [a] -> [a]
++ (Contents
v :: [Content])
    go' (Right Deref
m) = [Deref -> Content
ContentMixin Deref
m]

cssFileDebug :: Bool  -- ^ perform the indent-to-brace conversion
             -> Q Exp
             -> Parser [TopLevel 'Unresolved]
             -> FilePath
             -> Q Exp
cssFileDebug :: HasLeadingSpace
-> Q Exp -> Parser [TopLevel 'Unresolved] -> String -> Q Exp
cssFileDebug HasLeadingSpace
toi2b Q Exp
parseBlocks' Parser [TopLevel 'Unresolved]
parseBlocks String
fp = do
    String
s <- String -> Q String
readFileQ String
fp
    let vs :: [(Deref, VarType)]
vs = HasLeadingSpace
-> Parser [TopLevel 'Unresolved] -> String -> [(Deref, VarType)]
cssUsedIdentifiers HasLeadingSpace
toi2b Parser [TopLevel 'Unresolved]
parseBlocks String
s
    [Exp]
c <- ((Deref, VarType) -> Q Exp) -> [(Deref, VarType)] -> Q [Exp]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Deref, VarType) -> Q Exp
vtToExp [(Deref, VarType)]
vs
    Exp
cr <- [|cssRuntime toi2b|]
    Exp
parseBlocks'' <- Q Exp
parseBlocks'
    Exp -> Q Exp
forall (m :: * -> *) a. Monad m => a -> m a
return (Exp -> Q Exp) -> Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ Exp
cr Exp -> Exp -> Exp
`AppE` Exp
parseBlocks'' Exp -> Exp -> Exp
`AppE` (Lit -> Exp
LitE (Lit -> Exp) -> Lit -> Exp
forall a b. (a -> b) -> a -> b
$ String -> Lit
StringL String
fp) Exp -> Exp -> Exp
`AppE` [Exp] -> Exp
ListE [Exp]
c

runtimePrependSelector :: Builder -> (HasLeadingSpace, Block 'Resolved) -> Block 'Resolved
runtimePrependSelector :: Builder -> (HasLeadingSpace, Block 'Resolved) -> Block 'Resolved
runtimePrependSelector Builder
builder (HasLeadingSpace
hsl, BlockResolved Builder
x [Attr 'Resolved]
b) =
    Builder -> [Attr 'Resolved] -> Block 'Resolved
BlockResolved (Builder
builder Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder -> Builder
addSpace Builder
x) [Attr 'Resolved]
b
  where
    addSpace :: Builder -> Builder
addSpace = if HasLeadingSpace
hsl then (Char -> Builder
TLB.singleton Char
' ' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>) else Builder -> Builder
forall a. a -> a
id

combineSelectors :: HasLeadingSpace
                 -> [Contents]
                 -> [Contents]
                 -> [Contents]
combineSelectors :: HasLeadingSpace -> [Contents] -> [Contents] -> [Contents]
combineSelectors HasLeadingSpace
hsl [Contents]
a [Contents]
b = do
    Contents
a' <- [Contents]
a
    Contents
b' <- [Contents]
b
    Contents -> [Contents]
forall (m :: * -> *) a. Monad m => a -> m a
return (Contents -> [Contents]) -> Contents -> [Contents]
forall a b. (a -> b) -> a -> b
$ Contents
a' Contents -> Contents -> Contents
forall a. [a] -> [a] -> [a]
++ Contents -> Contents
addSpace Contents
b'
  where
    addSpace :: Contents -> Contents
addSpace
        | HasLeadingSpace
hsl = (String -> Content
ContentRaw String
" " Content -> Contents -> Contents
forall a. a -> [a] -> [a]
:)
        | HasLeadingSpace
otherwise = Contents -> Contents
forall a. a -> a
id

blockRuntime :: [(Deref, CDData url)]
             -> (url -> [(Text, Text)] -> Text)
             -> Block 'Unresolved
             -> Either String (DList (Block 'Resolved))
-- FIXME share code with blockToCss
blockRuntime :: [(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Block 'Unresolved
-> Either String (DList (Block 'Resolved))
blockRuntime [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
render' (BlockUnresolved [Contents]
x [Either (Attr 'Unresolved) Deref]
attrsAndMixins [(HasLeadingSpace, Block 'Unresolved)]
z) = do
    [Builder]
x' <- (Content -> Either String Builder)
-> Contents -> Either String [Builder]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Content -> Either String Builder
go' (Contents -> Either String [Builder])
-> Contents -> Either String [Builder]
forall a b. (a -> b) -> a -> b
$ Contents -> [Contents] -> Contents
forall a. [a] -> [[a]] -> [a]
intercalate [String -> Content
ContentRaw String
","] [Contents]
x
    [[Attr 'Resolved]]
attrs' <- (Either (Attr 'Unresolved) Deref -> Either String [Attr 'Resolved])
-> [Either (Attr 'Unresolved) Deref]
-> Either String [[Attr 'Resolved]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ((Attr 'Unresolved -> Either String [Attr 'Resolved])
-> (Deref -> Either String [Attr 'Resolved])
-> Either (Attr 'Unresolved) Deref
-> Either String [Attr 'Resolved]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Attr 'Unresolved -> Either String [Attr 'Resolved]
resolveAttr Deref -> Either String [Attr 'Resolved]
getMixinAttrs) [Either (Attr 'Unresolved) Deref]
attrsAndMixins
    [[(HasLeadingSpace, Block 'Resolved)]]
blocks' <- (Either (Attr 'Unresolved) Deref
 -> Either String [(HasLeadingSpace, Block 'Resolved)])
-> [Either (Attr 'Unresolved) Deref]
-> Either String [[(HasLeadingSpace, Block 'Resolved)]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ((Attr 'Unresolved
 -> Either String [(HasLeadingSpace, Block 'Resolved)])
-> (Deref -> Either String [(HasLeadingSpace, Block 'Resolved)])
-> Either (Attr 'Unresolved) Deref
-> Either String [(HasLeadingSpace, Block 'Resolved)]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Either String [(HasLeadingSpace, Block 'Resolved)]
-> Attr 'Unresolved
-> Either String [(HasLeadingSpace, Block 'Resolved)]
forall a b. a -> b -> a
const (Either String [(HasLeadingSpace, Block 'Resolved)]
 -> Attr 'Unresolved
 -> Either String [(HasLeadingSpace, Block 'Resolved)])
-> Either String [(HasLeadingSpace, Block 'Resolved)]
-> Attr 'Unresolved
-> Either String [(HasLeadingSpace, Block 'Resolved)]
forall a b. (a -> b) -> a -> b
$ [(HasLeadingSpace, Block 'Resolved)]
-> Either String [(HasLeadingSpace, Block 'Resolved)]
forall a b. b -> Either a b
Right []) Deref -> Either String [(HasLeadingSpace, Block 'Resolved)]
getMixinBlocks) [Either (Attr 'Unresolved) Deref]
attrsAndMixins
    [DList (Block 'Resolved)]
z' <- ((HasLeadingSpace, Block 'Unresolved)
 -> Either String (DList (Block 'Resolved)))
-> [(HasLeadingSpace, Block 'Unresolved)]
-> Either String [DList (Block 'Resolved)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ([Contents]
-> (HasLeadingSpace, Block 'Unresolved)
-> Either String (DList (Block 'Resolved))
subGo [Contents]
x) [(HasLeadingSpace, Block 'Unresolved)]
z -- FIXME use difflists again
    DList (Block 'Resolved) -> Either String (DList (Block 'Resolved))
forall a b. b -> Either a b
Right (DList (Block 'Resolved)
 -> Either String (DList (Block 'Resolved)))
-> DList (Block 'Resolved)
-> Either String (DList (Block 'Resolved))
forall a b. (a -> b) -> a -> b
$ \[Block 'Resolved]
rest -> BlockResolved :: Builder -> [Attr 'Resolved] -> Block 'Resolved
BlockResolved
        { brSelectors :: Builder
brSelectors = [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat [Builder]
x'
        , brAttrs :: [Attr 'Resolved]
brAttrs     = [[Attr 'Resolved]] -> [Attr 'Resolved]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Attr 'Resolved]]
attrs'
        }
        Block 'Resolved -> DList (Block 'Resolved)
forall a. a -> [a] -> [a]
: ((HasLeadingSpace, Block 'Resolved) -> Block 'Resolved)
-> [(HasLeadingSpace, Block 'Resolved)] -> [Block 'Resolved]
forall a b. (a -> b) -> [a] -> [b]
map (Builder -> (HasLeadingSpace, Block 'Resolved) -> Block 'Resolved
runtimePrependSelector (Builder -> (HasLeadingSpace, Block 'Resolved) -> Block 'Resolved)
-> Builder -> (HasLeadingSpace, Block 'Resolved) -> Block 'Resolved
forall a b. (a -> b) -> a -> b
$ [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat [Builder]
x') ([[(HasLeadingSpace, Block 'Resolved)]]
-> [(HasLeadingSpace, Block 'Resolved)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[(HasLeadingSpace, Block 'Resolved)]]
blocks')
        [Block 'Resolved] -> DList (Block 'Resolved)
forall a. [a] -> [a] -> [a]
++ (DList (Block 'Resolved) -> DList (Block 'Resolved))
-> [Block 'Resolved]
-> [DList (Block 'Resolved)]
-> [Block 'Resolved]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr DList (Block 'Resolved) -> DList (Block 'Resolved)
forall a b. (a -> b) -> a -> b
($) [Block 'Resolved]
rest [DList (Block 'Resolved)]
z'
    {-
    (:) (Css' (mconcat $ map go' $ intercalate [ContentRaw "," ] x) (map go'' y))
    . foldr (.) id (map (subGo x) z)
    -}
  where
    go' :: Content -> Either String Builder
go' = [(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Content
-> Either String Builder
forall url.
[(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Content
-> Either String Builder
contentToBuilderRT [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
render'

    getMixin :: Deref -> Either String Mixin
    getMixin :: Deref -> Either String Mixin
getMixin Deref
d =
        case Deref -> [(Deref, CDData url)] -> Maybe (CDData url)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Deref
d [(Deref, CDData url)]
cd of
            Maybe (CDData url)
Nothing -> String -> Either String Mixin
forall a b. a -> Either a b
Left (String -> Either String Mixin) -> String -> Either String Mixin
forall a b. (a -> b) -> a -> b
$ String
"Mixin not found: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Deref -> String
forall a. Show a => a -> String
show Deref
d
            Just (CDMixin Mixin
m) -> Mixin -> Either String Mixin
forall a b. b -> Either a b
Right Mixin
m
            Just CDData url
_ -> String -> Either String Mixin
forall a b. a -> Either a b
Left (String -> Either String Mixin) -> String -> Either String Mixin
forall a b. (a -> b) -> a -> b
$ String
"For " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Deref -> String
forall a. Show a => a -> String
show Deref
d String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
", expected Mixin"

    getMixinAttrs :: Deref -> Either String [Attr 'Resolved]
    getMixinAttrs :: Deref -> Either String [Attr 'Resolved]
getMixinAttrs = (Mixin -> [Attr 'Resolved])
-> Either String Mixin -> Either String [Attr 'Resolved]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Mixin -> [Attr 'Resolved]
mixinAttrs (Either String Mixin -> Either String [Attr 'Resolved])
-> (Deref -> Either String Mixin)
-> Deref
-> Either String [Attr 'Resolved]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Deref -> Either String Mixin
getMixin

    getMixinBlocks :: Deref -> Either String [(HasLeadingSpace, Block 'Resolved)]
    getMixinBlocks :: Deref -> Either String [(HasLeadingSpace, Block 'Resolved)]
getMixinBlocks = (Mixin -> [(HasLeadingSpace, Block 'Resolved)])
-> Either String Mixin
-> Either String [(HasLeadingSpace, Block 'Resolved)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Mixin -> [(HasLeadingSpace, Block 'Resolved)]
mixinBlocks (Either String Mixin
 -> Either String [(HasLeadingSpace, Block 'Resolved)])
-> (Deref -> Either String Mixin)
-> Deref
-> Either String [(HasLeadingSpace, Block 'Resolved)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Deref -> Either String Mixin
getMixin

    resolveAttr :: Attr 'Unresolved -> Either String [Attr 'Resolved]
    resolveAttr :: Attr 'Unresolved -> Either String [Attr 'Resolved]
resolveAttr (AttrUnresolved Contents
k Contents
v) =
      let eAttr :: Either String (Attr 'Resolved)
eAttr = Builder -> Builder -> Attr 'Resolved
AttrResolved (Builder -> Builder -> Attr 'Resolved)
-> Either String Builder
-> Either String (Builder -> Attr 'Resolved)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder)
-> Either String [Builder] -> Either String Builder
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Content -> Either String Builder)
-> Contents -> Either String [Builder]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Content -> Either String Builder
go' Contents
k) Either String (Builder -> Attr 'Resolved)
-> Either String Builder -> Either String (Attr 'Resolved)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ([Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder)
-> Either String [Builder] -> Either String Builder
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Content -> Either String Builder)
-> Contents -> Either String [Builder]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Content -> Either String Builder
go' Contents
v)
       in (Attr 'Resolved -> [Attr 'Resolved])
-> Either String (Attr 'Resolved) -> Either String [Attr 'Resolved]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Attr 'Resolved -> [Attr 'Resolved] -> [Attr 'Resolved]
forall a. a -> [a] -> [a]
:[]) Either String (Attr 'Resolved)
eAttr

    subGo :: [Contents] -- ^ parent selectors
          -> (HasLeadingSpace, Block 'Unresolved)
          -> Either String (DList (Block 'Resolved))
    subGo :: [Contents]
-> (HasLeadingSpace, Block 'Unresolved)
-> Either String (DList (Block 'Resolved))
subGo [Contents]
x' (HasLeadingSpace
hls, BlockUnresolved [Contents]
a [Either (Attr 'Unresolved) Deref]
b [(HasLeadingSpace, Block 'Unresolved)]
c) =
        let a' :: [Contents]
a' = HasLeadingSpace -> [Contents] -> [Contents] -> [Contents]
combineSelectors HasLeadingSpace
hls [Contents]
x' [Contents]
a
         in [(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Block 'Unresolved
-> Either String (DList (Block 'Resolved))
forall url.
[(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Block 'Unresolved
-> Either String (DList (Block 'Resolved))
blockRuntime [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
render' ([Contents]
-> [Either (Attr 'Unresolved) Deref]
-> [(HasLeadingSpace, Block 'Unresolved)]
-> Block 'Unresolved
BlockUnresolved [Contents]
a' [Either (Attr 'Unresolved) Deref]
b [(HasLeadingSpace, Block 'Unresolved)]
c)

contentToBuilderRT :: [(Deref, CDData url)]
                   -> (url -> [(Text, Text)] -> Text)
                   -> Content
                   -> Either String Builder
contentToBuilderRT :: [(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Content
-> Either String Builder
contentToBuilderRT [(Deref, CDData url)]
_ url -> [(Text, Text)] -> Text
_ (ContentRaw String
s) = Builder -> Either String Builder
forall a b. b -> Either a b
Right (Builder -> Either String Builder)
-> Builder -> Either String Builder
forall a b. (a -> b) -> a -> b
$ Text -> Builder
fromText (Text -> Builder) -> Text -> Builder
forall a b. (a -> b) -> a -> b
$ String -> Text
pack String
s
contentToBuilderRT [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
_ (ContentVar Deref
d) =
    case Deref -> [(Deref, CDData url)] -> Maybe (CDData url)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Deref
d [(Deref, CDData url)]
cd of
        Just (CDPlain Builder
s) -> Builder -> Either String Builder
forall a b. b -> Either a b
Right Builder
s
        Maybe (CDData url)
_ -> String -> Either String Builder
forall a b. a -> Either a b
Left (String -> Either String Builder)
-> String -> Either String Builder
forall a b. (a -> b) -> a -> b
$ Deref -> String
forall a. Show a => a -> String
show Deref
d String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": expected CDPlain"
contentToBuilderRT [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
render' (ContentUrl Deref
d) =
    case Deref -> [(Deref, CDData url)] -> Maybe (CDData url)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Deref
d [(Deref, CDData url)]
cd of
        Just (CDUrl url
u) -> Builder -> Either String Builder
forall a b. b -> Either a b
Right (Builder -> Either String Builder)
-> Builder -> Either String Builder
forall a b. (a -> b) -> a -> b
$ Text -> Builder
fromText (Text -> Builder) -> Text -> Builder
forall a b. (a -> b) -> a -> b
$ url -> [(Text, Text)] -> Text
render' url
u []
        Maybe (CDData url)
_ -> String -> Either String Builder
forall a b. a -> Either a b
Left (String -> Either String Builder)
-> String -> Either String Builder
forall a b. (a -> b) -> a -> b
$ Deref -> String
forall a. Show a => a -> String
show Deref
d String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": expected CDUrl"
contentToBuilderRT [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
render' (ContentUrlParam Deref
d) =
    case Deref -> [(Deref, CDData url)] -> Maybe (CDData url)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Deref
d [(Deref, CDData url)]
cd of
        Just (CDUrlParam (url
u, [(Text, Text)]
p)) ->
            Builder -> Either String Builder
forall a b. b -> Either a b
Right (Builder -> Either String Builder)
-> Builder -> Either String Builder
forall a b. (a -> b) -> a -> b
$ Text -> Builder
fromText (Text -> Builder) -> Text -> Builder
forall a b. (a -> b) -> a -> b
$ url -> [(Text, Text)] -> Text
render' url
u [(Text, Text)]
p
        Maybe (CDData url)
_ -> String -> Either String Builder
forall a b. a -> Either a b
Left (String -> Either String Builder)
-> String -> Either String Builder
forall a b. (a -> b) -> a -> b
$ Deref -> String
forall a. Show a => a -> String
show Deref
d String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": expected CDUrlParam"
contentToBuilderRT [(Deref, CDData url)]
_ url -> [(Text, Text)] -> Text
_ ContentMixin{} = String -> Either String Builder
forall a b. a -> Either a b
Left String
"contentToBuilderRT ContentMixin"

cssRuntime :: Bool -- ^ i2b?
           -> Parser [TopLevel 'Unresolved]
           -> FilePath
           -> [(Deref, CDData url)]
           -> (url -> [(Text, Text)] -> Text)
           -> Css
cssRuntime :: HasLeadingSpace
-> Parser [TopLevel 'Unresolved]
-> String
-> [(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Css
cssRuntime HasLeadingSpace
toi2b Parser [TopLevel 'Unresolved]
parseBlocks String
fp [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
render' = IO Css -> Css
forall a. IO a -> a
unsafePerformIO (IO Css -> Css) -> IO Css -> Css
forall a b. (a -> b) -> a -> b
$ do
    String
s' <- String -> IO String
readUtf8FileString String
fp
    let s :: String
s = if HasLeadingSpace
toi2b then ShowS
i2b String
s' else String
s'
    let a :: [TopLevel 'Unresolved]
a = (ParseError -> [TopLevel 'Unresolved])
-> ([TopLevel 'Unresolved] -> [TopLevel 'Unresolved])
-> Either ParseError [TopLevel 'Unresolved]
-> [TopLevel 'Unresolved]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> [TopLevel 'Unresolved]
forall a. HasCallStack => String -> a
error (String -> [TopLevel 'Unresolved])
-> (ParseError -> String) -> ParseError -> [TopLevel 'Unresolved]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseError -> String
forall a. Show a => a -> String
show) [TopLevel 'Unresolved] -> [TopLevel 'Unresolved]
forall a. a -> a
id (Either ParseError [TopLevel 'Unresolved]
 -> [TopLevel 'Unresolved])
-> Either ParseError [TopLevel 'Unresolved]
-> [TopLevel 'Unresolved]
forall a b. (a -> b) -> a -> b
$ Parser [TopLevel 'Unresolved]
-> String -> String -> Either ParseError [TopLevel 'Unresolved]
forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
parse Parser [TopLevel 'Unresolved]
parseBlocks String
s String
s
    Css -> IO Css
forall (m :: * -> *) a. Monad m => a -> m a
return (Css -> IO Css) -> Css -> IO Css
forall a b. (a -> b) -> a -> b
$ [TopLevel 'Resolved] -> Css
CssWhitespace ([TopLevel 'Resolved] -> Css) -> [TopLevel 'Resolved] -> Css
forall a b. (a -> b) -> a -> b
$ [(String, String)]
-> [TopLevel 'Unresolved] -> [TopLevel 'Resolved]
goTop [] [TopLevel 'Unresolved]
a
  where
    goTop :: [(String, String)] -- ^ scope
          -> [TopLevel 'Unresolved]
          -> [TopLevel 'Resolved]
    goTop :: [(String, String)]
-> [TopLevel 'Unresolved] -> [TopLevel 'Resolved]
goTop [(String, String)]
_ [] = []
    goTop [(String, String)]
scope (TopAtDecl String
dec Str 'Unresolved
cs':[TopLevel 'Unresolved]
rest) =
        String -> Str 'Resolved -> TopLevel 'Resolved
forall (a :: Resolved). String -> Str a -> TopLevel a
TopAtDecl String
dec Builder
Str 'Resolved
cs TopLevel 'Resolved -> [TopLevel 'Resolved] -> [TopLevel 'Resolved]
forall a. a -> [a] -> [a]
: [(String, String)]
-> [TopLevel 'Unresolved] -> [TopLevel 'Resolved]
goTop [(String, String)]
scope [TopLevel 'Unresolved]
rest
      where
        cs :: Builder
cs = (String -> Builder)
-> ([Builder] -> Builder) -> Either String [Builder] -> Builder
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Builder
forall a. HasCallStack => String -> a
error [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat (Either String [Builder] -> Builder)
-> Either String [Builder] -> Builder
forall a b. (a -> b) -> a -> b
$ (Content -> Either String Builder)
-> Contents -> Either String [Builder]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ([(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Content
-> Either String Builder
forall url.
[(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Content
-> Either String Builder
contentToBuilderRT [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
render') Contents
Str 'Unresolved
cs'
    goTop [(String, String)]
scope (TopBlock Block 'Unresolved
b:[TopLevel 'Unresolved]
rest) =
        (Block 'Resolved -> TopLevel 'Resolved)
-> [Block 'Resolved] -> [TopLevel 'Resolved]
forall a b. (a -> b) -> [a] -> [b]
map Block 'Resolved -> TopLevel 'Resolved
forall (a :: Resolved). Block a -> TopLevel a
TopBlock ((String -> [Block 'Resolved])
-> (DList (Block 'Resolved) -> [Block 'Resolved])
-> Either String (DList (Block 'Resolved))
-> [Block 'Resolved]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> [Block 'Resolved]
forall a. HasCallStack => String -> a
error (DList (Block 'Resolved) -> DList (Block 'Resolved)
forall a b. (a -> b) -> a -> b
$ []) (Either String (DList (Block 'Resolved)) -> [Block 'Resolved])
-> Either String (DList (Block 'Resolved)) -> [Block 'Resolved]
forall a b. (a -> b) -> a -> b
$ [(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Block 'Unresolved
-> Either String (DList (Block 'Resolved))
forall url.
[(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Block 'Unresolved
-> Either String (DList (Block 'Resolved))
blockRuntime ([(String, String)] -> [(Deref, CDData url)]
addScope [(String, String)]
scope) url -> [(Text, Text)] -> Text
render' Block 'Unresolved
b) [TopLevel 'Resolved]
-> [TopLevel 'Resolved] -> [TopLevel 'Resolved]
forall a. [a] -> [a] -> [a]
++
        [(String, String)]
-> [TopLevel 'Unresolved] -> [TopLevel 'Resolved]
goTop [(String, String)]
scope [TopLevel 'Unresolved]
rest
    goTop [(String, String)]
scope (TopAtBlock String
name Str 'Unresolved
s' [Block 'Unresolved]
b:[TopLevel 'Unresolved]
rest) =
        String -> Str 'Resolved -> [Block 'Resolved] -> TopLevel 'Resolved
forall (a :: Resolved). String -> Str a -> [Block a] -> TopLevel a
TopAtBlock String
name Builder
Str 'Resolved
s ((Block 'Unresolved -> DList (Block 'Resolved))
-> [Block 'Resolved] -> [Block 'Unresolved] -> [Block 'Resolved]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ((String -> DList (Block 'Resolved))
-> (DList (Block 'Resolved) -> DList (Block 'Resolved))
-> Either String (DList (Block 'Resolved))
-> DList (Block 'Resolved)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> DList (Block 'Resolved)
forall a. HasCallStack => String -> a
error DList (Block 'Resolved) -> DList (Block 'Resolved)
forall a. a -> a
id (Either String (DList (Block 'Resolved))
 -> DList (Block 'Resolved))
-> (Block 'Unresolved -> Either String (DList (Block 'Resolved)))
-> Block 'Unresolved
-> DList (Block 'Resolved)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Block 'Unresolved
-> Either String (DList (Block 'Resolved))
forall url.
[(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Block 'Unresolved
-> Either String (DList (Block 'Resolved))
blockRuntime ([(String, String)] -> [(Deref, CDData url)]
addScope [(String, String)]
scope) url -> [(Text, Text)] -> Text
render') [] [Block 'Unresolved]
b) TopLevel 'Resolved -> [TopLevel 'Resolved] -> [TopLevel 'Resolved]
forall a. a -> [a] -> [a]
:
        [(String, String)]
-> [TopLevel 'Unresolved] -> [TopLevel 'Resolved]
goTop [(String, String)]
scope [TopLevel 'Unresolved]
rest
      where
        s :: Builder
s = (String -> Builder)
-> ([Builder] -> Builder) -> Either String [Builder] -> Builder
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Builder
forall a. HasCallStack => String -> a
error [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat (Either String [Builder] -> Builder)
-> Either String [Builder] -> Builder
forall a b. (a -> b) -> a -> b
$ (Content -> Either String Builder)
-> Contents -> Either String [Builder]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ([(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Content
-> Either String Builder
forall url.
[(Deref, CDData url)]
-> (url -> [(Text, Text)] -> Text)
-> Content
-> Either String Builder
contentToBuilderRT [(Deref, CDData url)]
cd url -> [(Text, Text)] -> Text
render') Contents
Str 'Unresolved
s'
    goTop [(String, String)]
scope (TopVar String
k String
v:[TopLevel 'Unresolved]
rest) = [(String, String)]
-> [TopLevel 'Unresolved] -> [TopLevel 'Resolved]
goTop ((String
k, String
v)(String, String) -> [(String, String)] -> [(String, String)]
forall a. a -> [a] -> [a]
:[(String, String)]
scope) [TopLevel 'Unresolved]
rest

    addScope :: [(String, String)] -> [(Deref, CDData url)]
addScope [(String, String)]
scope = ((String, String) -> (Deref, CDData url))
-> [(String, String)] -> [(Deref, CDData url)]
forall a b. (a -> b) -> [a] -> [b]
map (Ident -> Deref
DerefIdent (Ident -> Deref) -> (String -> Ident) -> String -> Deref
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Ident
Ident (String -> Deref)
-> (String -> CDData url)
-> (String, String)
-> (Deref, CDData url)
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** Builder -> CDData url
forall url. Builder -> CDData url
CDPlain (Builder -> CDData url)
-> (String -> Builder) -> String -> CDData url
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Builder
fromString) [(String, String)]
scope [(Deref, CDData url)]
-> [(Deref, CDData url)] -> [(Deref, CDData url)]
forall a. [a] -> [a] -> [a]
++ [(Deref, CDData url)]
cd

vtToExp :: (Deref, VarType) -> Q Exp
vtToExp :: (Deref, VarType) -> Q Exp
vtToExp (Deref
d, VarType
vt) = do
    Exp
d' <- Deref -> Q Exp
forall t. Lift t => t -> Q Exp
lift Deref
d
    Exp
c' <- VarType -> Q Exp
c VarType
vt
    Exp -> Q Exp
forall (m :: * -> *) a. Monad m => a -> m a
return (Exp -> Q Exp) -> Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ [Maybe Exp] -> Exp
TupE
#if MIN_VERSION_template_haskell(2,16,0)
      ([Maybe Exp] -> Exp) -> [Maybe Exp] -> Exp
forall a b. (a -> b) -> a -> b
$ (Exp -> Maybe Exp) -> [Exp] -> [Maybe Exp]
forall a b. (a -> b) -> [a] -> [b]
map Exp -> Maybe Exp
forall a. a -> Maybe a
Just
#endif
      [Exp
d', Exp
c' Exp -> Exp -> Exp
`AppE` Scope -> Deref -> Exp
derefToExp [] Deref
d]
  where
    c :: VarType -> Q Exp
    c :: VarType -> Q Exp
c VarType
VTPlain = [|CDPlain . toCss|]
    c VarType
VTUrl = [|CDUrl|]
    c VarType
VTUrlParam = [|CDUrlParam|]
    c VarType
VTMixin = [|CDMixin|]

getVars :: [(String, String)] -> Content -> Either String [(Deref, VarType)]
getVars :: [(String, String)] -> Content -> Either String [(Deref, VarType)]
getVars [(String, String)]
_ ContentRaw{} = [(Deref, VarType)] -> Either String [(Deref, VarType)]
forall (m :: * -> *) a. Monad m => a -> m a
return []
getVars [(String, String)]
scope (ContentVar Deref
d) =
    case Deref -> [(String, String)] -> Maybe String
forall b. Deref -> [(String, b)] -> Maybe String
lookupD Deref
d [(String, String)]
scope of
        Just String
_ -> [(Deref, VarType)] -> Either String [(Deref, VarType)]
forall (m :: * -> *) a. Monad m => a -> m a
return []
        Maybe String
Nothing -> [(Deref, VarType)] -> Either String [(Deref, VarType)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(Deref
d, VarType
VTPlain)]
getVars [(String, String)]
scope (ContentUrl Deref
d) =
    case Deref -> [(String, String)] -> Maybe String
forall b. Deref -> [(String, b)] -> Maybe String
lookupD Deref
d [(String, String)]
scope of
        Maybe String
Nothing -> [(Deref, VarType)] -> Either String [(Deref, VarType)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(Deref
d, VarType
VTUrl)]
        Just String
s -> String -> Either String [(Deref, VarType)]
forall a b. a -> Either a b
Left (String -> Either String [(Deref, VarType)])
-> String -> Either String [(Deref, VarType)]
forall a b. (a -> b) -> a -> b
$ String
"Expected URL for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s
getVars [(String, String)]
scope (ContentUrlParam Deref
d) =
    case Deref -> [(String, String)] -> Maybe String
forall b. Deref -> [(String, b)] -> Maybe String
lookupD Deref
d [(String, String)]
scope of
        Maybe String
Nothing -> [(Deref, VarType)] -> Either String [(Deref, VarType)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(Deref
d, VarType
VTUrlParam)]
        Just String
s -> String -> Either String [(Deref, VarType)]
forall a b. a -> Either a b
Left (String -> Either String [(Deref, VarType)])
-> String -> Either String [(Deref, VarType)]
forall a b. (a -> b) -> a -> b
$ String
"Expected URLParam for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s
getVars [(String, String)]
scope (ContentMixin Deref
d) =
    case Deref -> [(String, String)] -> Maybe String
forall b. Deref -> [(String, b)] -> Maybe String
lookupD Deref
d [(String, String)]
scope of
        Maybe String
Nothing -> [(Deref, VarType)] -> Either String [(Deref, VarType)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(Deref
d, VarType
VTMixin)]
        Just String
s -> String -> Either String [(Deref, VarType)]
forall a b. a -> Either a b
Left (String -> Either String [(Deref, VarType)])
-> String -> Either String [(Deref, VarType)]
forall a b. (a -> b) -> a -> b
$ String
"Expected Mixin for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s

lookupD :: Deref -> [(String, b)] -> Maybe String
lookupD :: Deref -> [(String, b)] -> Maybe String
lookupD (DerefIdent (Ident String
s)) [(String, b)]
scope =
    case String -> [(String, b)] -> Maybe b
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
s [(String, b)]
scope of
        Maybe b
Nothing -> Maybe String
forall a. Maybe a
Nothing
        Just b
_ -> String -> Maybe String
forall a. a -> Maybe a
Just String
s
lookupD Deref
_ [(String, b)]
_ = Maybe String
forall a. Maybe a
Nothing

compressTopLevel :: TopLevel 'Unresolved
                 -> TopLevel 'Unresolved
compressTopLevel :: TopLevel 'Unresolved -> TopLevel 'Unresolved
compressTopLevel (TopBlock Block 'Unresolved
b) = Block 'Unresolved -> TopLevel 'Unresolved
forall (a :: Resolved). Block a -> TopLevel a
TopBlock (Block 'Unresolved -> TopLevel 'Unresolved)
-> Block 'Unresolved -> TopLevel 'Unresolved
forall a b. (a -> b) -> a -> b
$ Block 'Unresolved -> Block 'Unresolved
compressBlock Block 'Unresolved
b
compressTopLevel (TopAtBlock String
name Str 'Unresolved
s [Block 'Unresolved]
b) = String
-> Str 'Unresolved -> [Block 'Unresolved] -> TopLevel 'Unresolved
forall (a :: Resolved). String -> Str a -> [Block a] -> TopLevel a
TopAtBlock String
name Str 'Unresolved
s ([Block 'Unresolved] -> TopLevel 'Unresolved)
-> [Block 'Unresolved] -> TopLevel 'Unresolved
forall a b. (a -> b) -> a -> b
$ (Block 'Unresolved -> Block 'Unresolved)
-> [Block 'Unresolved] -> [Block 'Unresolved]
forall a b. (a -> b) -> [a] -> [b]
map Block 'Unresolved -> Block 'Unresolved
compressBlock [Block 'Unresolved]
b
compressTopLevel x :: TopLevel 'Unresolved
x@TopAtDecl{} = TopLevel 'Unresolved
x
compressTopLevel x :: TopLevel 'Unresolved
x@TopVar{} = TopLevel 'Unresolved
x

compressBlock :: Block 'Unresolved
              -> Block 'Unresolved
compressBlock :: Block 'Unresolved -> Block 'Unresolved
compressBlock (BlockUnresolved [Contents]
x [Either (Attr 'Unresolved) Deref]
y [(HasLeadingSpace, Block 'Unresolved)]
blocks) =
    [Contents]
-> [Either (Attr 'Unresolved) Deref]
-> [(HasLeadingSpace, Block 'Unresolved)]
-> Block 'Unresolved
BlockUnresolved ((Contents -> Contents) -> [Contents] -> [Contents]
forall a b. (a -> b) -> [a] -> [b]
map Contents -> Contents
cc [Contents]
x) ((Either (Attr 'Unresolved) Deref
 -> Either (Attr 'Unresolved) Deref)
-> [Either (Attr 'Unresolved) Deref]
-> [Either (Attr 'Unresolved) Deref]
forall a b. (a -> b) -> [a] -> [b]
map Either (Attr 'Unresolved) Deref -> Either (Attr 'Unresolved) Deref
go [Either (Attr 'Unresolved) Deref]
y) (((HasLeadingSpace, Block 'Unresolved)
 -> (HasLeadingSpace, Block 'Unresolved))
-> [(HasLeadingSpace, Block 'Unresolved)]
-> [(HasLeadingSpace, Block 'Unresolved)]
forall a b. (a -> b) -> [a] -> [b]
map ((Block 'Unresolved -> Block 'Unresolved)
-> (HasLeadingSpace, Block 'Unresolved)
-> (HasLeadingSpace, Block 'Unresolved)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second Block 'Unresolved -> Block 'Unresolved
compressBlock) [(HasLeadingSpace, Block 'Unresolved)]
blocks)
  where
    go :: Either (Attr 'Unresolved) Deref -> Either (Attr 'Unresolved) Deref
    go :: Either (Attr 'Unresolved) Deref -> Either (Attr 'Unresolved) Deref
go (Left (AttrUnresolved Contents
k Contents
v)) = Attr 'Unresolved -> Either (Attr 'Unresolved) Deref
forall a b. a -> Either a b
Left (Attr 'Unresolved -> Either (Attr 'Unresolved) Deref)
-> Attr 'Unresolved -> Either (Attr 'Unresolved) Deref
forall a b. (a -> b) -> a -> b
$ Contents -> Contents -> Attr 'Unresolved
AttrUnresolved (Contents -> Contents
cc Contents
k) (Contents -> Contents
cc Contents
v)
    go (Right Deref
m) = Deref -> Either (Attr 'Unresolved) Deref
forall a b. b -> Either a b
Right Deref
m
    cc :: Contents -> Contents
    cc :: Contents -> Contents
cc [] = []
    cc (ContentRaw String
a:ContentRaw String
b:Contents
c) = Contents -> Contents
cc (Contents -> Contents) -> Contents -> Contents
forall a b. (a -> b) -> a -> b
$ String -> Content
ContentRaw (String
a String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
b) Content -> Contents -> Contents
forall a. a -> [a] -> [a]
: Contents
c
    cc (Content
a:Contents
b) = Content
a Content -> Contents -> Contents
forall a. a -> [a] -> [a]
: Contents -> Contents
cc Contents
b

blockToMixin :: Name
             -> Scope
             -> Block 'Unresolved
             -> Q Exp
blockToMixin :: Name -> [(String, String)] -> Block 'Unresolved -> Q Exp
blockToMixin Name
r [(String, String)]
scope (BlockUnresolved [Contents]
_sel [Either (Attr 'Unresolved) Deref]
props [(HasLeadingSpace, Block 'Unresolved)]
subblocks) =
    -- TODO: preserve the CPS in @mixinBlocks@ below
    [| let attrsAndMixins = $(processAttrsAndDerefs r scope props)
        in Mixin
            { mixinAttrs =
                concatMap (either (:[]) mixinAttrs) attrsAndMixins
            , mixinBlocks =
                concat $
                  $(listE $ map subGo subblocks)
                  ++ map (either (const []) mixinBlocks) attrsAndMixins
            }
    |]
  where
    -- We don't use the @hls@ to combine selectors, because the parent
    -- selector for a mixin is the dummy @mixin@ selector. But we may want
    -- to know later if the block needs a leading space, because the mixin
    -- might include an @&@ which needs to mix correctly with the parent
    -- block's selector.
    subGo :: (HasLeadingSpace, Block 'Unresolved) -> Q Exp
subGo (HasLeadingSpace
hls, BlockUnresolved [Contents]
sel' [Either (Attr 'Unresolved) Deref]
b [(HasLeadingSpace, Block 'Unresolved)]
c) =
      [| map (\x -> ($(lift hls), x))
           $ $(blockToCss r scope $ BlockUnresolved sel' b c) []
      |]
        
blockToCss :: Name
           -> Scope
           -> Block 'Unresolved
           -> ExpQ
blockToCss :: Name -> [(String, String)] -> Block 'Unresolved -> Q Exp
blockToCss Name
r [(String, String)]
scope (BlockUnresolved [Contents]
sel [Either (Attr 'Unresolved) Deref]
props [(HasLeadingSpace, Block 'Unresolved)]
subblocks) =
    [| let attrsAndMixins = $(processAttrsAndDerefs r scope props)
           selToBuilder = $(selectorToBuilder r scope sel)
       in ( BlockResolved
            { brSelectors = selToBuilder
            , brAttrs     = concatMap (either (:[]) mixinAttrs) attrsAndMixins
            }:)
          . foldr (.) id $(listE $ map subGo subblocks)
          . (fmap
                (runtimePrependSelector selToBuilder)
                (concatMap (either (const []) mixinBlocks) attrsAndMixins) ++)
    |]
  where
    subGo :: (HasLeadingSpace, Block 'Unresolved) -> Q Exp
    subGo :: (HasLeadingSpace, Block 'Unresolved) -> Q Exp
subGo (HasLeadingSpace
hls, BlockUnresolved [Contents]
sel' [Either (Attr 'Unresolved) Deref]
b [(HasLeadingSpace, Block 'Unresolved)]
c) =
        let sel'' :: [Contents]
sel'' = HasLeadingSpace -> [Contents] -> [Contents] -> [Contents]
combineSelectors HasLeadingSpace
hls [Contents]
sel [Contents]
sel'
         in Name -> [(String, String)] -> Block 'Unresolved -> Q Exp
blockToCss Name
r [(String, String)]
scope (Block 'Unresolved -> Q Exp) -> Block 'Unresolved -> Q Exp
forall a b. (a -> b) -> a -> b
$ [Contents]
-> [Either (Attr 'Unresolved) Deref]
-> [(HasLeadingSpace, Block 'Unresolved)]
-> Block 'Unresolved
BlockUnresolved [Contents]
sel'' [Either (Attr 'Unresolved) Deref]
b [(HasLeadingSpace, Block 'Unresolved)]
c


processAttrsAndDerefs ::
     Name
  -> Scope
  -> [Either (Attr 'Unresolved) Deref]
  -> Q Exp -- ^ Either (Attr 'Resolved) Mixin
processAttrsAndDerefs :: Name
-> [(String, String)] -> [Either (Attr 'Unresolved) Deref] -> Q Exp
processAttrsAndDerefs Name
r [(String, String)]
scope [Either (Attr 'Unresolved) Deref]
props = [Q Exp] -> Q Exp
listE ([Q Exp] -> Q Exp) -> [Q Exp] -> Q Exp
forall a b. (a -> b) -> a -> b
$ (Either (Attr 'Unresolved) Deref -> Q Exp)
-> [Either (Attr 'Unresolved) Deref] -> [Q Exp]
forall a b. (a -> b) -> [a] -> [b]
map Either (Attr 'Unresolved) Deref -> Q Exp
go [Either (Attr 'Unresolved) Deref]
props
  where
    go :: Either (Attr 'Unresolved) Deref -> Q Exp
go (Right Deref
deref) = Exp -> Q Exp
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Exp -> Q Exp) -> Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ Name -> Exp
ConE 'Right Exp -> Exp -> Exp
`AppE` (Scope -> Deref -> Exp
derefToExp [] Deref
deref)
    go (Left (AttrUnresolved Contents
x Contents
y)) =
          Name -> Q Exp
conE 'Left Q Exp -> Q Exp -> Q Exp
`appE`
            ( Name -> Q Exp
conE 'AttrResolved
                Q Exp -> Q Exp -> Q Exp
`appE` (Name -> [(String, String)] -> Contents -> Q Exp
contentsToBuilder Name
r [(String, String)]
scope Contents
x)
                Q Exp -> Q Exp -> Q Exp
`appE` (Name -> [(String, String)] -> Contents -> Q Exp
contentsToBuilder Name
r [(String, String)]
scope Contents
y)
            )

selectorToBuilder :: Name -> Scope -> [Contents] -> Q Exp
selectorToBuilder :: Name -> [(String, String)] -> [Contents] -> Q Exp
selectorToBuilder Name
r [(String, String)]
scope [Contents]
sels =
    Name -> [(String, String)] -> Contents -> Q Exp
contentsToBuilder Name
r [(String, String)]
scope (Contents -> Q Exp) -> Contents -> Q Exp
forall a b. (a -> b) -> a -> b
$ Contents -> [Contents] -> Contents
forall a. [a] -> [[a]] -> [a]
intercalate [String -> Content
ContentRaw String
","] [Contents]
sels

contentsToBuilder :: Name -> Scope -> [Content] -> Q Exp
contentsToBuilder :: Name -> [(String, String)] -> Contents -> Q Exp
contentsToBuilder Name
r [(String, String)]
scope Contents
contents =
    Q Exp -> Q Exp -> Q Exp
appE [|mconcat|] (Q Exp -> Q Exp) -> Q Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ [Q Exp] -> Q Exp
listE ([Q Exp] -> Q Exp) -> [Q Exp] -> Q Exp
forall a b. (a -> b) -> a -> b
$ (Content -> Q Exp) -> Contents -> [Q Exp]
forall a b. (a -> b) -> [a] -> [b]
map (Name -> [(String, String)] -> Content -> Q Exp
contentToBuilder Name
r [(String, String)]
scope) Contents
contents

contentToBuilder :: Name -> Scope -> Content -> Q Exp
contentToBuilder :: Name -> [(String, String)] -> Content -> Q Exp
contentToBuilder Name
_ [(String, String)]
_ (ContentRaw String
x) =
    [|fromText . pack|] Q Exp -> Q Exp -> Q Exp
`appE` Lit -> Q Exp
litE (String -> Lit
StringL String
x)
contentToBuilder Name
_ [(String, String)]
scope (ContentVar Deref
d) =
    case Deref
d of
        DerefIdent (Ident String
s)
            | Just String
val <- String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
s [(String, String)]
scope -> [|fromText . pack|] Q Exp -> Q Exp -> Q Exp
`appE` Lit -> Q Exp
litE (String -> Lit
StringL String
val)
        Deref
_ -> [|toCss|] Q Exp -> Q Exp -> Q Exp
`appE` Exp -> Q Exp
forall (m :: * -> *) a. Monad m => a -> m a
return (Scope -> Deref -> Exp
derefToExp [] Deref
d)
contentToBuilder Name
r [(String, String)]
_ (ContentUrl Deref
u) =
    [|fromText|] Q Exp -> Q Exp -> Q Exp
`appE`
        (Name -> Q Exp
varE Name
r Q Exp -> Q Exp -> Q Exp
`appE` Exp -> Q Exp
forall (m :: * -> *) a. Monad m => a -> m a
return (Scope -> Deref -> Exp
derefToExp [] Deref
u) Q Exp -> Q Exp -> Q Exp
`appE` [Q Exp] -> Q Exp
listE [])
contentToBuilder Name
r [(String, String)]
_ (ContentUrlParam Deref
u) =
    [|fromText|] Q Exp -> Q Exp -> Q Exp
`appE`
        ([|uncurry|] Q Exp -> Q Exp -> Q Exp
`appE` Name -> Q Exp
varE Name
r Q Exp -> Q Exp -> Q Exp
`appE` Exp -> Q Exp
forall (m :: * -> *) a. Monad m => a -> m a
return (Scope -> Deref -> Exp
derefToExp [] Deref
u))
contentToBuilder Name
_ [(String, String)]
_ ContentMixin{} = String -> Q Exp
forall a. HasCallStack => String -> a
error String
"contentToBuilder on ContentMixin"

type Scope = [(String, String)]

topLevelsToCassius :: [TopLevel 'Unresolved]
                   -> Q Exp
topLevelsToCassius :: [TopLevel 'Unresolved] -> Q Exp
topLevelsToCassius [TopLevel 'Unresolved]
a = do
    Name
r <- String -> Q Name
newName String
"_render"
    [PatQ] -> Q Exp -> Q Exp
lamE [Name -> PatQ
varP Name
r] (Q Exp -> Q Exp) -> Q Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ Q Exp -> Q Exp -> Q Exp
appE [|CssNoWhitespace . foldr ($) []|] (Q Exp -> Q Exp) -> Q Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ ([Exp] -> Exp) -> Q [Exp] -> Q Exp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Exp] -> Exp
ListE (Q [Exp] -> Q Exp) -> Q [Exp] -> Q Exp
forall a b. (a -> b) -> a -> b
$ Name -> [(String, String)] -> [TopLevel 'Unresolved] -> Q [Exp]
go Name
r [] [TopLevel 'Unresolved]
a
  where
    go :: Name -> [(String, String)] -> [TopLevel 'Unresolved] -> Q [Exp]
go Name
_ [(String, String)]
_ [] = [Exp] -> Q [Exp]
forall (m :: * -> *) a. Monad m => a -> m a
return []
    go Name
r [(String, String)]
scope (TopBlock Block 'Unresolved
b:[TopLevel 'Unresolved]
rest) = do
        Exp
e <- [|(++) $ map TopBlock ($(blockToCss r scope b) [])|]
        [Exp]
es <- Name -> [(String, String)] -> [TopLevel 'Unresolved] -> Q [Exp]
go Name
r [(String, String)]
scope [TopLevel 'Unresolved]
rest
        [Exp] -> Q [Exp]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Exp] -> Q [Exp]) -> [Exp] -> Q [Exp]
forall a b. (a -> b) -> a -> b
$ Exp
e Exp -> [Exp] -> [Exp]
forall a. a -> [a] -> [a]
: [Exp]
es
    go Name
r [(String, String)]
scope (TopAtBlock String
name Str 'Unresolved
s [Block 'Unresolved]
b:[TopLevel 'Unresolved]
rest) = do
        let s' :: Q Exp
s' = Name -> [(String, String)] -> Contents -> Q Exp
contentsToBuilder Name
r [(String, String)]
scope Contents
Str 'Unresolved
s
        Exp
e <- [|(:) $ TopAtBlock $(lift name) $(s') $(blocksToCassius r scope b)|]
        [Exp]
es <- Name -> [(String, String)] -> [TopLevel 'Unresolved] -> Q [Exp]
go Name
r [(String, String)]
scope [TopLevel 'Unresolved]
rest
        [Exp] -> Q [Exp]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Exp] -> Q [Exp]) -> [Exp] -> Q [Exp]
forall a b. (a -> b) -> a -> b
$ Exp
e Exp -> [Exp] -> [Exp]
forall a. a -> [a] -> [a]
: [Exp]
es
    go Name
r [(String, String)]
scope (TopAtDecl String
dec Str 'Unresolved
cs:[TopLevel 'Unresolved]
rest) = do
        Exp
e <- [|(:) $ TopAtDecl $(lift dec) $(contentsToBuilder r scope cs)|]
        [Exp]
es <- Name -> [(String, String)] -> [TopLevel 'Unresolved] -> Q [Exp]
go Name
r [(String, String)]
scope [TopLevel 'Unresolved]
rest
        [Exp] -> Q [Exp]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Exp] -> Q [Exp]) -> [Exp] -> Q [Exp]
forall a b. (a -> b) -> a -> b
$ Exp
e Exp -> [Exp] -> [Exp]
forall a. a -> [a] -> [a]
: [Exp]
es
    go Name
r [(String, String)]
scope (TopVar String
k String
v:[TopLevel 'Unresolved]
rest) = Name -> [(String, String)] -> [TopLevel 'Unresolved] -> Q [Exp]
go Name
r ((String
k, String
v) (String, String) -> [(String, String)] -> [(String, String)]
forall a. a -> [a] -> [a]
: [(String, String)]
scope) [TopLevel 'Unresolved]
rest

blocksToCassius :: Name
                -> Scope
                -> [Block 'Unresolved]
                -> Q Exp
blocksToCassius :: Name -> [(String, String)] -> [Block 'Unresolved] -> Q Exp
blocksToCassius Name
r [(String, String)]
scope [Block 'Unresolved]
a = do
    Q Exp -> Q Exp -> Q Exp
appE [|foldr ($) []|] (Q Exp -> Q Exp) -> Q Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ [Q Exp] -> Q Exp
listE ([Q Exp] -> Q Exp) -> [Q Exp] -> Q Exp
forall a b. (a -> b) -> a -> b
$ (Block 'Unresolved -> Q Exp) -> [Block 'Unresolved] -> [Q Exp]
forall a b. (a -> b) -> [a] -> [b]
map (Name -> [(String, String)] -> Block 'Unresolved -> Q Exp
blockToCss Name
r [(String, String)]
scope) [Block 'Unresolved]
a

renderCss :: Css -> TL.Text
renderCss :: Css -> Text
renderCss Css
css =
    Builder -> Text
toLazyText (Builder -> Text) -> Builder -> Text
forall a b. (a -> b) -> a -> b
$ [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder) -> [Builder] -> Builder
forall a b. (a -> b) -> a -> b
$ (TopLevel 'Resolved -> Builder)
-> [TopLevel 'Resolved] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map TopLevel 'Resolved -> Builder
go [TopLevel 'Resolved]
tops
  where
    (HasLeadingSpace
haveWhiteSpace, [TopLevel 'Resolved]
tops) =
        case Css
css of
            CssWhitespace [TopLevel 'Resolved]
x -> (HasLeadingSpace
True, [TopLevel 'Resolved]
x)
            CssNoWhitespace [TopLevel 'Resolved]
x -> (HasLeadingSpace
False, [TopLevel 'Resolved]
x)
    go :: TopLevel 'Resolved -> Builder
go (TopBlock Block 'Resolved
x) = HasLeadingSpace -> Builder -> Block 'Resolved -> Builder
renderBlock HasLeadingSpace
haveWhiteSpace Builder
forall a. Monoid a => a
mempty Block 'Resolved
x
    go (TopAtBlock String
name Str 'Resolved
s [Block 'Resolved]
x) =
        Text -> Builder
fromText (String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"@", String
name, String
" "]) Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend`
        Builder
Str 'Resolved
s Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend`
        Builder
startBlock Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend`
        (Builder -> Builder -> Builder) -> Builder -> [Builder] -> Builder
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
mappend Builder
endBlock ((Block 'Resolved -> Builder) -> [Block 'Resolved] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (HasLeadingSpace -> Builder -> Block 'Resolved -> Builder
renderBlock HasLeadingSpace
haveWhiteSpace (String -> Builder
fromString String
"    ")) [Block 'Resolved]
x)
    go (TopAtDecl String
dec Str 'Resolved
cs) = Text -> Builder
fromText (String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"@", String
dec, String
" "]) Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend`
                      Builder
Str 'Resolved
cs Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend`
                      Builder
endDecl

    startBlock :: Builder
startBlock
        | HasLeadingSpace
haveWhiteSpace = String -> Builder
fromString String
" {\n"
        | HasLeadingSpace
otherwise = Char -> Builder
singleton Char
'{'

    endBlock :: Builder
endBlock
        | HasLeadingSpace
haveWhiteSpace = String -> Builder
fromString String
"}\n"
        | HasLeadingSpace
otherwise = Char -> Builder
singleton Char
'}'

    endDecl :: Builder
endDecl
        | HasLeadingSpace
haveWhiteSpace = String -> Builder
fromString String
";\n"
        | HasLeadingSpace
otherwise = Char -> Builder
singleton Char
';'

renderBlock :: Bool -- ^ have whitespace?
            -> Builder -- ^ indentation
            -> Block 'Resolved
            -> Builder
renderBlock :: HasLeadingSpace -> Builder -> Block 'Resolved -> Builder
renderBlock HasLeadingSpace
haveWhiteSpace Builder
indent (BlockResolved Builder
sel [Attr 'Resolved]
attrs)
    | [Attr 'Resolved] -> HasLeadingSpace
forall (t :: * -> *) a. Foldable t => t a -> HasLeadingSpace
null [Attr 'Resolved]
attrs = Builder
forall a. Monoid a => a
mempty
    | HasLeadingSpace
otherwise = Builder
startSelect
               Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
sel
               Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
startBlock
               Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat (Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
intersperse Builder
endDecl ([Builder] -> [Builder]) -> [Builder] -> [Builder]
forall a b. (a -> b) -> a -> b
$ (Attr 'Resolved -> Builder) -> [Attr 'Resolved] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map Attr 'Resolved -> Builder
renderAttr [Attr 'Resolved]
attrs)
               Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
endBlock
  where
    renderAttr :: Attr 'Resolved -> Builder
renderAttr (AttrResolved Builder
k Builder
v) = Builder
startDecl Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
k Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
colon Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
v

    colon :: Builder
colon
        | HasLeadingSpace
haveWhiteSpace = String -> Builder
fromString String
": "
        | HasLeadingSpace
otherwise = Char -> Builder
singleton Char
':'

    startSelect :: Builder
startSelect
        | HasLeadingSpace
haveWhiteSpace = Builder
indent
        | HasLeadingSpace
otherwise = Builder
forall a. Monoid a => a
mempty

    startBlock :: Builder
startBlock
        | HasLeadingSpace
haveWhiteSpace = String -> Builder
fromString String
" {\n"
        | HasLeadingSpace
otherwise = Char -> Builder
singleton Char
'{'

    endBlock :: Builder
endBlock
        | HasLeadingSpace
haveWhiteSpace = String -> Builder
fromString String
";\n" Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Builder
indent Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` String -> Builder
fromString String
"}\n"
        | HasLeadingSpace
otherwise = Char -> Builder
singleton Char
'}'

    startDecl :: Builder
startDecl
        | HasLeadingSpace
haveWhiteSpace = Builder
indent Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` String -> Builder
fromString String
"    "
        | HasLeadingSpace
otherwise = Builder
forall a. Monoid a => a
mempty

    endDecl :: Builder
endDecl
        | HasLeadingSpace
haveWhiteSpace = String -> Builder
fromString String
";\n"
        | HasLeadingSpace
otherwise = Char -> Builder
singleton Char
';'

instance Lift (Attr a) where
  lift :: Attr a -> Q Exp
lift = \case
    AttrResolved Builder
k Builder
v -> [|AttrResolved $(liftBuilder k) $(liftBuilder v)|]
    AttrUnresolved Contents
k Contents
v -> [|AttrUnresolved k v|]
#if MIN_VERSION_template_haskell(2,17,0)
  liftTyped = unsafeCodeCoerce . lift
#elif MIN_VERSION_template_haskell(2,16,0)
  liftTyped :: Attr a -> Q (TExp (Attr a))
liftTyped = Q Exp -> Q (TExp (Attr a))
forall a. Q Exp -> Q (TExp a)
unsafeTExpCoerce (Q Exp -> Q (TExp (Attr a)))
-> (Attr a -> Q Exp) -> Attr a -> Q (TExp (Attr a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Attr a -> Q Exp
forall t. Lift t => t -> Q Exp
lift
#endif

#if MIN_VERSION_template_haskell(2,17,0)
liftBuilder :: Quote m => Builder -> m Exp
#else
liftBuilder :: Builder -> Q Exp
#endif
liftBuilder :: Builder -> Q Exp
liftBuilder Builder
b = [|fromText $ pack $(lift $ TL.unpack $ toLazyText b)|]

instance Lift (Block a) where
  lift :: Block a -> Q Exp
lift = \case
    BlockResolved Builder
a [Attr 'Resolved]
b -> [|BlockResolved $(liftBuilder a) b|]
    BlockUnresolved [Contents]
a [Either (Attr 'Unresolved) Deref]
b [(HasLeadingSpace, Block 'Unresolved)]
c -> [|BlockUnresolved a b c|]
#if MIN_VERSION_template_haskell(2,17,0)
  liftTyped = unsafeCodeCoerce . lift
#elif MIN_VERSION_template_haskell(2,16,0)
  liftTyped :: Block a -> Q (TExp (Block a))
liftTyped = Q Exp -> Q (TExp (Block a))
forall a. Q Exp -> Q (TExp a)
unsafeTExpCoerce (Q Exp -> Q (TExp (Block a)))
-> (Block a -> Q Exp) -> Block a -> Q (TExp (Block a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Block a -> Q Exp
forall t. Lift t => t -> Q Exp
lift
#endif