    {-# LANGUAGE OverloadedStrings #-}
    -- | Manipulate CSS urls.
    --
    -- * Make relative urls absolute (useful when combining assets)
    module Yesod.EmbeddedStatic.Css.AbsoluteUrl (
      -- * Absolute urls
        absoluteUrls
      , absoluteUrlsAt
      , absoluteUrlsWith
      , absCssUrlsFileProd
      , absCssUrlsProd
    ) where

    import Yesod.EmbeddedStatic.Generators
    import Yesod.EmbeddedStatic.Types

    import qualified Data.ByteString.Lazy as BL
    import qualified Data.Text as T
    import qualified Data.Text.Lazy as TL
    import qualified Data.Text.IO as T
    import qualified Data.Text.Lazy.Encoding as TL
    import Control.Monad ((>=>))
    import Data.Maybe (fromMaybe)
    import System.FilePath ((</>))

    import Yesod.EmbeddedStatic.Css.Util

    -------------------------------------------------------------------------------
    -- Generator
    -------------------------------------------------------------------------------

    -- | Anchors relative CSS image urls
    absCssUrlsFileProd :: FilePath -- ^ Anchor relative urls to here
                         -> FilePath
                         -> IO BL.ByteString
    absCssUrlsFileProd :: FilePath -> FilePath -> IO ByteString
    absCssUrlsFileProd FilePath
    dir FilePath
    file = do
        contents <- FilePath -> IO Text
    T.readFile FilePath
    file
        return $ TL.encodeUtf8 $ absCssUrlsProd dir contents

    absCssUrlsProd :: FilePath -- ^ Anchor relative urls to here
                   -> T.Text
                   -> TL.Text
    absCssUrlsProd :: FilePath -> Text -> Text
    absCssUrlsProd FilePath
    dir Text
    contents =
        let css :: Css
    css = (FilePath -> Css) -> (Css -> Css) -> Either FilePath Css -> Css
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either FilePath -> Css
    forall a. HasCallStack => FilePath -> a
    error Css -> Css
    forall a. a -> a
    id (Either FilePath Css -> Css) -> Either FilePath Css -> Css
    forall a b. (a -> b) -> a -> b
    $ Text -> Either FilePath Css
    parseCssUrls Text
    contents
        in  (UrlReference -> Text) -> Css -> Text
    renderCssWith UrlReference -> Text
    toAbsoluteUrl Css
    css
      where
        toAbsoluteUrl :: UrlReference -> Text
    toAbsoluteUrl (UrlReference Text
    rel) = [Text] -> Text
    T.concat
            [ Text
    "url('/"
            , (FilePath -> Text
    T.pack (FilePath -> Text) -> FilePath -> Text
    forall a b. (a -> b) -> a -> b
    $ FilePath
    dir FilePath -> FilePath -> FilePath
    </> Text -> FilePath
    T.unpack Text
    rel)
            , Text
    "')"
            ]

    -- | Equivalent to passing the same string twice to 'absoluteUrlsAt'.
    absoluteUrls :: FilePath -> Generator
    absoluteUrls :: FilePath -> Generator
    absoluteUrls FilePath
    f = FilePath -> FilePath -> Generator
    absoluteUrlsAt FilePath
    f FilePath
    f

    -- | Equivalent to passing @return@ to 'absoluteUrlsWith'.
    absoluteUrlsAt :: Location -> FilePath -> Generator
    absoluteUrlsAt :: FilePath -> FilePath -> Generator
    absoluteUrlsAt FilePath
    loc FilePath
    f = FilePath
    -> FilePath -> Maybe (CssGeneration -> IO ByteString) -> Generator
    absoluteUrlsWith FilePath
    loc FilePath
    f Maybe (CssGeneration -> IO ByteString)
    forall a. Maybe a
    Nothing

    -- | Automatically make relative urls absolute
    --
    -- During development, leave CSS as is.
    --
    -- When CSS is organized into a directory structure, it will work properly for individual requests for each file.
    -- During production, we want to combine and minify CSS as much as possible.
    -- The combination process combines files from different directories, messing up relative urls.
    -- This pre-processor makes relative urls absolute
    absoluteUrlsWith ::
        Location -- ^ The location the CSS file should appear in the static subsite
      -> FilePath -- ^ Path to the CSS file.
      -> Maybe (CssGeneration -> IO BL.ByteString) -- ^ Another filter function run after this one (for example @return . yuiCSS . cssContent@) or other CSS filter that runs after this filter.
                         -> Generator
    absoluteUrlsWith :: FilePath
    -> FilePath -> Maybe (CssGeneration -> IO ByteString) -> Generator
    absoluteUrlsWith FilePath
    loc FilePath
    file Maybe (CssGeneration -> IO ByteString)
    mpostFilter =
        [Entry] -> Generator
    forall a. a -> Q a
    forall (m :: * -> *) a. Monad m => a -> m a
    return [ (FilePath -> IO ByteString) -> FilePath -> FilePath -> Entry
    cssProductionFilter (FilePath -> FilePath -> IO ByteString
    absCssUrlsFileProd FilePath
    loc (FilePath -> IO ByteString)
    -> (ByteString -> IO ByteString) -> FilePath -> IO ByteString
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> CssGeneration -> IO ByteString
    postFilter (CssGeneration -> IO ByteString)
    -> (ByteString -> CssGeneration) -> ByteString -> IO ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . FilePath -> FilePath -> ByteString -> CssGeneration
    mkCssGeneration FilePath
    loc FilePath
    file) FilePath
    loc FilePath
    file
        ]
      where
        postFilter :: CssGeneration -> IO ByteString
    postFilter = (CssGeneration -> IO ByteString)
    -> Maybe (CssGeneration -> IO ByteString)
    -> CssGeneration
    -> IO ByteString
    forall a. a -> Maybe a -> a
    fromMaybe (ByteString -> IO ByteString
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ByteString -> IO ByteString)
    -> (CssGeneration -> ByteString) -> CssGeneration -> IO ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CssGeneration -> ByteString
    cssContent) Maybe (CssGeneration -> IO ByteString)
    mpostFilter