module Buffet.Document.DocumentInternal ( get ) where import qualified Buffet.Document.Configuration as Configuration import qualified Buffet.Document.TemplateContext as TemplateContext import qualified Buffet.Ir.Ir as Ir import qualified Buffet.Toolbox.ExceptionTools as ExceptionTools import qualified Buffet.Toolbox.TextTools as TextTools import qualified Control.Exception as Exception import qualified Data.Aeson as Aeson import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Text as T import Prelude ( FilePath , IO , Show , ($) , (.) , (<>) , fmap , maybe , pure , show , unlines ) import qualified System.FilePath as FilePath import qualified Text.Mustache as Mustache import qualified Text.Mustache.Render as Render import qualified Text.Mustache.Types as Types import qualified Text.Parsec as Parsec data Exception = CompileException Parsec.ParseError | SubstituteException FilePath (NonEmpty.NonEmpty Render.SubstitutionError) instance Show Exception where show (CompileException error) = show error show (SubstituteException path errors) = unlines . NonEmpty.toList . NonEmpty.cons (path <> ":") $ fmap show' errors where show' (Render.VariableNotFound name) = "Variable not found: " <> showName name show' (Render.InvalidImplicitSectionContextType valueType) = "Invalid implicit section context type: " <> valueType show' Render.InvertedImplicitSection = "Inverted implicit section" show' (Render.SectionTargetNotFound name) = "Section target not found: " <> showName name show' (Render.PartialNotFound path') = "Partial not found: " <> path' show' (Render.DirectlyRenderedValue value) = "Directly rendered value: " <> show value showName = T.unpack . T.intercalate (T.pack ".") instance Exception.Exception Exception get :: Configuration.Configuration -> Ir.Buffet -> IO T.Text get configuration = maybe (pure . printTemplateContext) renderTemplate (Configuration.template configuration) . TemplateContext.get printTemplateContext :: Aeson.Value -> T.Text printTemplateContext = TextTools.prettyPrintJson renderTemplate :: FilePath -> Aeson.Value -> IO T.Text renderTemplate templatePath templateContext = do template <- getTemplate templatePath let (errors, result) = Mustache.checkedSubstitute template $ Types.mFromJSON templateContext maybe (pure result) (Exception.throwIO . SubstituteException templatePath) $ NonEmpty.nonEmpty errors getTemplate :: FilePath -> IO Mustache.Template getTemplate templatePath = ExceptionTools.eitherThrow CompileException $ Mustache.automaticCompile searchSpace templatePath where searchSpace = [".", FilePath.takeDirectory templatePath]