pdf-slave-template-1.2.0.0: src/Text/PDF/Slave/Template.hs
-- | Defines document template
module Text.PDF.Slave.Template(
TemplateName
, TemplateInput
, TemplateBody
, TemplateBibtex
, DependencyBody
, BibTexBody
, TemplateDependency(..)
, Template(..)
, TemplateDependencyFile(..)
, TemplateFile(..)
) where
import Control.Monad (mzero, unless)
import Data.ByteString (ByteString)
import Data.Monoid
import Data.Text as T
import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Base64 as B64
import qualified Data.Map.Strict as M
import qualified Data.Text.Encoding as T
-- | Template unique name
type TemplateName = Text
-- | A template takes simple YAML document as input
type TemplateInput = Value
-- | Template body is text with .htex content
type TemplateBody = Text
-- | Template can define additional bibtex database
type TemplateBibtex = Text
-- | Dependency can be a binary file
type DependencyBody = ByteString
-- | Content of bibtex file
type BibTexBody = Text
-- | Template has different types of dependencies, each type of the dependecy
-- has own affect on rendering pipe.
data TemplateDependency =
-- | Bibtex file for references to other documents. Need call to bibtex
BibtexDep BibTexBody
-- | HTex file that need to be compiled to .tex file
| TemplateDep Template
-- | HTex file that need to be compiled to .pdf file
| TemplatePdfDep Template
-- | Any other file that doesn't need a compilation (listings, images, etc)
| OtherDep DependencyBody
deriving (Generic, Show)
instance FromJSON TemplateDependency where
parseJSON val@(Object o) = do
depType <- o .: "type"
case T.toLower . T.strip $ depType of
"bibtex" -> BibtexDep <$> o .: "body"
"template" -> TemplateDep <$> parseJSON val
"template_pdf" -> TemplatePdfDep <$> parseJSON val
"other" -> do
(t :: Text) <- o .: "body"
either (\e -> fail $ "Cannot decode dependency body (base64): " <> e) (return . OtherDep) $
B64.decode . T.encodeUtf8 $ t
_ -> fail $ "Unknown template type " <> unpack depType
parseJSON _ = mzero
instance ToJSON TemplateDependency where
toJSON d = case d of
BibtexDep body -> object [
"type" .= ("bibtex" :: Text)
, "body" .= body
]
TemplateDep body -> let
Object o1 = object [ "type" .= ("template" :: Text) ]
Object o2 = toJSON body
in Object (o1 <> o2)
TemplatePdfDep body -> let
Object o1 = object [ "type" .= ("template_pdf" :: Text) ]
Object o2 = toJSON body
in Object (o1 <> o2)
OtherDep bs -> object [
"type" .= ("other" :: Text)
, "body" .= (T.decodeUtf8 . B64.encode $ bs)
]
-- | Description of document template
data Template = Template {
-- | Template has human readable name
templateName :: TemplateName
-- | Template expects input in YAML format
, templateInput :: Maybe TemplateInput
-- | Template contents
, templateBody :: TemplateBody
-- | Template dependencies (bibtex, listings, other htex files)
, templateDeps :: M.Map TemplateName TemplateDependency
-- | Additional flags for `haskintex`
, templateHaskintexOpts :: [Text]
} deriving (Generic, Show)
instance FromJSON Template where
parseJSON (Object o) = do
flag <- o .: "bundle"
unless flag $ fail "Expected bundle template format, but got ordinary template"
Template
<$> o .: "name"
<*> o .:? "input"
<*> o .: "body"
<*> o .:? "dependencies" .!= mempty
<*> o .:? "haskintex-opts" .!= mempty
parseJSON _ = mzero
instance ToJSON Template where
toJSON Template{..} = object [
"name" .= templateName
, "input" .= templateInput
, "body" .= templateBody
, "dependencies" .= templateDeps
, "haskintex-opts" .= templateHaskintexOpts
, "bundle" .= True
]
-- | Same as 'TemplateDependency' but keeps contents in separate files
data TemplateDependencyFile =
-- | Bibtex file for references to other documents. Need call to bibtex.
-- Name of dependency is a filename with contents.
BibtexDepFile
-- | HTex file that need to be compiled to .tex file
-- Name of dependency defines a subfolder for the template.
| TemplateDepFile TemplateFile
-- | HTex file that need to be compiled to .pdf file
-- Name of dependency deinfes a subfolder for the template.
| TemplatePdfDepFile TemplateFile
-- | Any other file that doesn't need a compilation (listings, images, etc)
-- Name of dependency is a filename with contents.
| OtherDepFile
deriving (Generic, Show)
instance FromJSON TemplateDependencyFile where
parseJSON val@(Object o) = do
depType <- o .: "type"
case T.toLower . T.strip $ depType of
"bibtex" -> pure BibtexDepFile
"template" -> TemplateDepFile <$> parseJSON val
"template_pdf" -> TemplatePdfDepFile <$> parseJSON val
"other" -> pure OtherDepFile
_ -> fail $ "Unknown template type " <> unpack depType
parseJSON _ = mzero
instance ToJSON TemplateDependencyFile where
toJSON d = case d of
BibtexDepFile -> object [
"type" .= ("bibtex" :: Text)
]
TemplateDepFile body -> let
Object o1 = object [ "type" .= ("template" :: Text) ]
Object o2 = toJSON body
in Object (o1 <> o2)
TemplatePdfDepFile body -> let
Object o1 = object [ "type" .= ("template_pdf" :: Text) ]
Object o2 = toJSON body
in Object (o1 <> o2)
OtherDepFile -> object [
"type" .= ("other" :: Text)
]
-- | Same as 'Template', but holds info about template content and dependencies
-- in other files.
data TemplateFile = TemplateFile {
-- | Template has human readable name
templateFileName :: TemplateName
-- | Template expects input in JSON format. The field contains filename of the YAML file.
, templateFileInput :: Maybe Text
-- | Template contents filename.
, templateFileBody :: Text
-- | Template dependencies (bibtex, listings, other htex files)
, templateFileDeps :: M.Map TemplateName TemplateDependencyFile
-- | Additional flags for `haskintex`
, templateFileHaskintexOpts :: [Text]
} deriving (Generic, Show)
instance FromJSON TemplateFile where
parseJSON (Object o) = do
mflag <- o .:? "bundle"
case mflag of
Just True -> fail "Expected ordinary template format, but got bundle template"
_ -> return ()
TemplateFile
<$> o .: "name"
<*> o .:? "input"
<*> o .: "body"
<*> o .:? "dependencies" .!= mempty
<*> o .:? "haskintex-opts" .!= mempty
parseJSON _ = mzero
instance ToJSON TemplateFile where
toJSON TemplateFile{..} = object [
"name" .= templateFileName
, "input" .= templateFileInput
, "body" .= templateFileBody
, "dependencies" .= templateFileDeps
, "haskintex-opts" .= templateFileHaskintexOpts
]