-- | Simple templating using HTML5 as the template language. Templates are -- specified by adding special attributes to tags. During substitution, these -- attributes are stripped from the HTML. The following attributes are -- recognized: -- -- * @insert="identifier"@ - replace the tag's contents with the value -- bound to @identifier@ in the substitution context. -- * @replace="identifier"@ - replace the whole tag and its contents with -- the value bound to @identifier@ in the substitution context. -- * @when="identifier"@ - only render this tag if @identifier@ is set to -- true in the substitution context. -- * @unless="identifier"@ - the dual of @when@; only render this tag if -- @identifier@ is set to false in the substitution context. -- * @forall="identifier"@ - render this tag and its contents once for each -- element in the list bound to @identifier@ in the substitution context. -- The contents of the element may refer to the current iteration's value -- of @identifier@ by that same name. -- -- Substitution can also be performed on the attributes of tags. The -- following attribute substitutions are recognized: -- -- * @when:identifier:attr="value"@ - only include @attr@ is @identifier@ -- is set to true in the substitution context. -- * @unless:identifier:attr="value"@ - only include @attr@ is @identifier@ -- is set to false in the substitution context. -- * @insert:identifier:attr="value"@ - overwrite the value of @attr@ with -- whatever @identifier@ is bound to in the substitution context. -- -- Contexts can be nested, in which case nested keys are separated by -- periods, as in @parent.child.grandchild@. Keys may be prefixed with a -- question mark, in which case they are considered to be "weak keys". -- If a weak key does not exist in the context, it will be replaced by a -- sensible default value instead of causing an error. The defaults for the -- different value types are as follows: -- -- * bool: false -- * string: "" -- * array: [] -- * object: {} -- -- As numbers are treated just like strings, they have an empty string as -- their default value as well. -- -- In general, values used as text must be declared text by the context and -- so on, but the following coercions are permitted: -- -- * bool to string -- * array to bool -- -- Coercion of array to bool, with the empty list being considered false and -- all other list considered true, is permitted to allow templates to take -- special action in the case of an empty list. -- -- Contexts may be constructed programatically using the provided -- combinators, converted from JSON objects or lists of key-value pairs, or -- parsed from a YAML-formatted string using 'parseContext'. module Text.Domplate ( Text, Monoid, Template, Context, Value (..), Key, parseTemplate, replace, add, remove, fromList, Text.Domplate.Context.lookup, empty, size, (<>), parseContext, compile ) where import Control.Applicative hiding (empty) import Data.Monoid import Data.Text (Text) import Data.Yaml (Value (..)) import Text.Domplate.Context import Text.Domplate.Replace import qualified Data.ByteString as BS (readFile, writeFile) -- | Compile a template using a context parsed from a context file. -- Throws an error if context parsing or substitution fails. compile :: FilePath -- ^ Template file. -> FilePath -- ^ Context file. -> FilePath -- ^ Output file. -> IO () compile template context outfile = do t <- parseTemplate <$> BS.readFile template ec <- parseContext <$> BS.readFile context case fmapL show ec >>= replace t of Right s -> BS.writeFile outfile s Left e -> error e fmapL :: (a -> b) -> Either a c -> Either b c fmapL f (Left x) = Left (f x) fmapL _ (Right x) = Right x