{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
module Text.EDE
(
Template,
parse,
parseIO,
parseFile,
parseFileWith,
parseWith,
Resolver,
Id,
includeMap,
includeFile,
render,
renderWith,
eitherParse,
eitherParseFile,
eitherParseWith,
eitherRender,
eitherRenderWith,
Trifecta.Delta.Delta (..),
Result (..),
eitherResult,
result,
success,
failure,
fromValue,
fromPairs,
(.=),
version,
Delim,
Syntax,
delimPragma,
delimInline,
delimComment,
delimBlock,
defaultSyntax,
alternateSyntax,
)
where
import qualified Control.Monad as Monad
import Data.Aeson ((.=))
import Data.Aeson.Types (Value)
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import qualified Data.Foldable as Foldable
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.List.NonEmpty (NonEmpty (..))
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Lazy as Text.Lazy
import qualified Data.Text.Lazy.Builder as Text.Builder
import Data.Version (Version)
import qualified Paths_ede as Paths
import Prettyprinter (Pretty (..))
import qualified System.Directory as Directory
import qualified System.FilePath as FilePath
import qualified Text.EDE.Internal.Eval as Eval
import qualified Text.EDE.Internal.Parser as Parser
import Text.EDE.Internal.Quoting (Term)
import Text.EDE.Internal.Syntax
import Text.EDE.Internal.Types
import qualified Text.Trifecta.Delta as Trifecta.Delta
version :: Version
version :: Version
version = Version
Paths.version
parse ::
ByteString ->
Result Template
parse :: ByteString -> Result Template
parse = Result (Result Template) -> Result Template
forall (m :: * -> *) a. Monad m => m (m a) -> m a
Monad.join (Result (Result Template) -> Result Template)
-> (ByteString -> Result (Result Template))
-> ByteString
-> Result Template
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Syntax
-> Resolver Result -> Id -> ByteString -> Result (Result Template)
forall (m :: * -> *).
Monad m =>
Syntax -> Resolver m -> Id -> ByteString -> m (Result Template)
parseWith Syntax
defaultSyntax (HashMap Id Template -> Resolver Result
forall (m :: * -> *). Monad m => HashMap Id Template -> Resolver m
includeMap HashMap Id Template
forall a. Monoid a => a
mempty) Id
"Text.EDE.parse"
parseIO ::
FilePath ->
ByteString ->
IO (Result Template)
parseIO :: FilePath -> ByteString -> IO (Result Template)
parseIO FilePath
p = Syntax -> Resolver IO -> Id -> ByteString -> IO (Result Template)
forall (m :: * -> *).
Monad m =>
Syntax -> Resolver m -> Id -> ByteString -> m (Result Template)
parseWith Syntax
defaultSyntax (FilePath -> Resolver IO
includeFile FilePath
p) Id
"Text.EDE.parse"
parseFile ::
FilePath ->
IO (Result Template)
parseFile :: FilePath -> IO (Result Template)
parseFile = Syntax -> FilePath -> IO (Result Template)
parseFileWith Syntax
defaultSyntax
parseFileWith ::
Syntax ->
FilePath ->
IO (Result Template)
parseFileWith :: Syntax -> FilePath -> IO (Result Template)
parseFileWith Syntax
s FilePath
p =
FilePath -> IO (Result ByteString)
loadFile FilePath
p
IO (Result ByteString)
-> (Result ByteString -> IO (Result Template))
-> IO (Result Template)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (AnsiDoc -> IO (Result Template))
-> (ByteString -> IO (Result Template))
-> Result ByteString
-> IO (Result Template)
forall b a. (AnsiDoc -> b) -> (a -> b) -> Result a -> b
result
AnsiDoc -> IO (Result Template)
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure
(Syntax -> Resolver IO -> Id -> ByteString -> IO (Result Template)
forall (m :: * -> *).
Monad m =>
Syntax -> Resolver m -> Id -> ByteString -> m (Result Template)
parseWith Syntax
s (FilePath -> Resolver IO
includeFile (FilePath -> FilePath
FilePath.takeDirectory FilePath
p)) (FilePath -> Id
Text.pack FilePath
p))
parseWith ::
Monad m =>
Syntax ->
Resolver m ->
Text ->
ByteString ->
m (Result Template)
parseWith :: forall (m :: * -> *).
Monad m =>
Syntax -> Resolver m -> Id -> ByteString -> m (Result Template)
parseWith Syntax
config Resolver m
f Id
name ByteString
input =
case Syntax
-> Id
-> ByteString
-> Result
(Exp Delta, HashMap Id (NonEmpty Delta),
HashMap Id (NonEmpty Delta), HashMap Id (Exp Delta))
Parser.runParser Syntax
config Id
name ByteString
input of
Success (Exp Delta
u, HashMap Id (NonEmpty Delta)
is', HashMap Id (NonEmpty Delta)
es', HashMap Id (Exp Delta)
bs) -> do
Result (HashMap Id (Exp Delta))
is <- ((Id, NonEmpty Delta)
-> Result (HashMap Id (Exp Delta))
-> m (Result (HashMap Id (Exp Delta))))
-> Result (HashMap Id (Exp Delta))
-> [(Id, NonEmpty Delta)]
-> m (Result (HashMap Id (Exp Delta)))
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> b -> m b) -> b -> t a -> m b
Foldable.foldrM (Id, NonEmpty Delta)
-> Result (HashMap Id (Exp Delta))
-> m (Result (HashMap Id (Exp Delta)))
include (HashMap Id (Exp Delta) -> Result (HashMap Id (Exp Delta))
forall a. a -> Result a
Success (Id -> Exp Delta -> HashMap Id (Exp Delta)
forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton Id
name Exp Delta
u)) (HashMap Id (NonEmpty Delta) -> [(Id, NonEmpty Delta)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap Id (NonEmpty Delta)
is')
Result (HashMap Id (Exp Delta))
es <- ((Id, NonEmpty Delta)
-> Result (HashMap Id (Exp Delta))
-> m (Result (HashMap Id (Exp Delta))))
-> Result (HashMap Id (Exp Delta))
-> [(Id, NonEmpty Delta)]
-> m (Result (HashMap Id (Exp Delta)))
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> b -> m b) -> b -> t a -> m b
Foldable.foldrM (Id, NonEmpty Delta)
-> Result (HashMap Id (Exp Delta))
-> m (Result (HashMap Id (Exp Delta)))
extends (HashMap Id (Exp Delta) -> Result (HashMap Id (Exp Delta))
forall a. a -> Result a
Success HashMap Id (Exp Delta)
forall a. Monoid a => a
mempty) (HashMap Id (NonEmpty Delta) -> [(Id, NonEmpty Delta)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap Id (NonEmpty Delta)
es')
Result Template -> m (Result Template)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Id
-> Exp Delta
-> HashMap Id (Exp Delta)
-> HashMap Id (Exp Delta)
-> HashMap Id (Exp Delta)
-> Template
Template Id
name Exp Delta
u (HashMap Id (Exp Delta)
-> HashMap Id (Exp Delta) -> HashMap Id (Exp Delta) -> Template)
-> Result (HashMap Id (Exp Delta))
-> Result
(HashMap Id (Exp Delta) -> HashMap Id (Exp Delta) -> Template)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Result (HashMap Id (Exp Delta))
is Result
(HashMap Id (Exp Delta) -> HashMap Id (Exp Delta) -> Template)
-> Result (HashMap Id (Exp Delta))
-> Result (HashMap Id (Exp Delta) -> Template)
forall a b. Result (a -> b) -> Result a -> Result b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Result (HashMap Id (Exp Delta))
es Result (HashMap Id (Exp Delta) -> Template)
-> Result (HashMap Id (Exp Delta)) -> Result Template
forall a b. Result (a -> b) -> Result a -> Result b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> HashMap Id (Exp Delta) -> Result (HashMap Id (Exp Delta))
forall a. a -> Result a
forall (f :: * -> *) a. Applicative f => a -> f a
pure HashMap Id (Exp Delta)
bs)
Failure AnsiDoc
err ->
AnsiDoc -> m (Result Template)
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure AnsiDoc
err
where
include :: (Id, NonEmpty Delta)
-> Result (HashMap Id (Exp Delta))
-> m (Result (HashMap Id (Exp Delta)))
include (Id
_, NonEmpty Delta
_) (Failure AnsiDoc
err) = AnsiDoc -> m (Result (HashMap Id (Exp Delta)))
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure AnsiDoc
err
include (Id
key, Delta
delta :| [Delta]
_) (Success HashMap Id (Exp Delta)
ss) =
Resolver m
f Syntax
config Id
key Delta
delta
m (Result Template)
-> (Result Template -> m (Result (HashMap Id (Exp Delta))))
-> m (Result (HashMap Id (Exp Delta)))
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (AnsiDoc -> m (Result (HashMap Id (Exp Delta))))
-> (Template -> m (Result (HashMap Id (Exp Delta))))
-> Result Template
-> m (Result (HashMap Id (Exp Delta)))
forall b a. (AnsiDoc -> b) -> (a -> b) -> Result a -> b
result AnsiDoc -> m (Result (HashMap Id (Exp Delta)))
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure (HashMap Id (Exp Delta) -> m (Result (HashMap Id (Exp Delta)))
forall (m :: * -> *) a. Monad m => a -> m (Result a)
success (HashMap Id (Exp Delta) -> m (Result (HashMap Id (Exp Delta))))
-> (Template -> HashMap Id (Exp Delta))
-> Template
-> m (Result (HashMap Id (Exp Delta)))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Id (Exp Delta)
-> HashMap Id (Exp Delta) -> HashMap Id (Exp Delta)
forall a. Monoid a => a -> a -> a
mappend HashMap Id (Exp Delta)
ss (HashMap Id (Exp Delta) -> HashMap Id (Exp Delta))
-> (Template -> HashMap Id (Exp Delta))
-> Template
-> HashMap Id (Exp Delta)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Template -> HashMap Id (Exp Delta)
_tmplIncl)
extends :: (Id, NonEmpty Delta)
-> Result (HashMap Id (Exp Delta))
-> m (Result (HashMap Id (Exp Delta)))
extends (Id
_, NonEmpty Delta
_) (Failure AnsiDoc
err) = AnsiDoc -> m (Result (HashMap Id (Exp Delta)))
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure AnsiDoc
err
extends (Id
key, Delta
delta :| [Delta]
_) (Success HashMap Id (Exp Delta)
ss) =
Resolver m
f Syntax
config Id
key Delta
delta
m (Result Template)
-> (Result Template -> m (Result (HashMap Id (Exp Delta))))
-> m (Result (HashMap Id (Exp Delta)))
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (AnsiDoc -> m (Result (HashMap Id (Exp Delta))))
-> (Template -> m (Result (HashMap Id (Exp Delta))))
-> Result Template
-> m (Result (HashMap Id (Exp Delta)))
forall b a. (AnsiDoc -> b) -> (a -> b) -> Result a -> b
result AnsiDoc -> m (Result (HashMap Id (Exp Delta)))
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure (HashMap Id (Exp Delta) -> m (Result (HashMap Id (Exp Delta)))
forall (m :: * -> *) a. Monad m => a -> m (Result a)
success (HashMap Id (Exp Delta) -> m (Result (HashMap Id (Exp Delta))))
-> (Template -> HashMap Id (Exp Delta))
-> Template
-> m (Result (HashMap Id (Exp Delta)))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Id (Exp Delta)
-> HashMap Id (Exp Delta) -> HashMap Id (Exp Delta)
forall a. Monoid a => a -> a -> a
mappend HashMap Id (Exp Delta)
ss (HashMap Id (Exp Delta) -> HashMap Id (Exp Delta))
-> (Template -> HashMap Id (Exp Delta))
-> Template
-> HashMap Id (Exp Delta)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Template -> HashMap Id (Exp Delta)
_tmplIncl)
includeMap ::
Monad m =>
HashMap Id Template ->
Resolver m
includeMap :: forall (m :: * -> *). Monad m => HashMap Id Template -> Resolver m
includeMap HashMap Id Template
templates Syntax
_config Id
key Delta
_delta
| Just Template
val <- Id -> HashMap Id Template -> Maybe Template
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Id
key HashMap Id Template
templates = Template -> m (Result Template)
forall (m :: * -> *) a. Monad m => a -> m (Result a)
success Template
val
| Bool
otherwise = AnsiDoc -> m (Result Template)
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure (AnsiDoc
"unable to resolve " AnsiDoc -> AnsiDoc -> AnsiDoc
forall a. Semigroup a => a -> a -> a
<> FilePath -> AnsiDoc
forall ann. FilePath -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty (Id -> FilePath
Text.unpack Id
key))
includeFile ::
FilePath ->
Resolver IO
includeFile :: FilePath -> Resolver IO
includeFile FilePath
path Syntax
config Id
key Delta
_delta =
FilePath -> IO (Result ByteString)
loadFile FilePath
file IO (Result ByteString)
-> (Result ByteString -> IO (Result Template))
-> IO (Result Template)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (AnsiDoc -> IO (Result Template))
-> (ByteString -> IO (Result Template))
-> Result ByteString
-> IO (Result Template)
forall b a. (AnsiDoc -> b) -> (a -> b) -> Result a -> b
result AnsiDoc -> IO (Result Template)
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure (Syntax -> Resolver IO -> Id -> ByteString -> IO (Result Template)
forall (m :: * -> *).
Monad m =>
Syntax -> Resolver m -> Id -> ByteString -> m (Result Template)
parseWith Syntax
config Resolver IO
include Id
key)
where
include :: Resolver IO
include :: Resolver IO
include = FilePath -> Resolver IO
includeFile (FilePath -> FilePath
FilePath.takeDirectory FilePath
file)
file :: FilePath
file
| Id -> Bool
Text.null Id
key = Id -> FilePath
Text.unpack Id
key
| Bool
otherwise = FilePath -> FilePath -> FilePath
FilePath.combine FilePath
path (Id -> FilePath
Text.unpack Id
key)
loadFile :: FilePath -> IO (Result ByteString)
loadFile :: FilePath -> IO (Result ByteString)
loadFile FilePath
path = do
Bool
exists <- FilePath -> IO Bool
Directory.doesFileExist FilePath
path
if Bool -> Bool
not Bool
exists
then AnsiDoc -> IO (Result ByteString)
forall (m :: * -> *) a. Monad m => AnsiDoc -> m (Result a)
failure (AnsiDoc
"file " AnsiDoc -> AnsiDoc -> AnsiDoc
forall a. Semigroup a => a -> a -> a
<> FilePath -> AnsiDoc
forall ann. FilePath -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty FilePath
path AnsiDoc -> AnsiDoc -> AnsiDoc
forall a. Semigroup a => a -> a -> a
<> AnsiDoc
" doesn't exist.")
else FilePath -> IO ByteString
ByteString.readFile FilePath
path IO ByteString
-> (ByteString -> IO (Result ByteString)) -> IO (Result ByteString)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString -> IO (Result ByteString)
forall (m :: * -> *) a. Monad m => a -> m (Result a)
success
render ::
Template ->
HashMap Text Value ->
Result Text.Lazy.Text
render :: Template -> HashMap Id Value -> Result Text
render = HashMap Id Term -> Template -> HashMap Id Value -> Result Text
renderWith HashMap Id Term
forall a. Monoid a => a
mempty
renderWith ::
HashMap Id Term ->
Template ->
HashMap Text Value ->
Result Text.Lazy.Text
renderWith :: HashMap Id Term -> Template -> HashMap Id Value -> Result Text
renderWith HashMap Id Term
fs Template
t =
(Builder -> Text) -> Result Builder -> Result Text
forall a b. (a -> b) -> Result a -> Result b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Builder -> Text
Text.Builder.toLazyText (Result Builder -> Result Text)
-> (HashMap Id Value -> Result Builder)
-> HashMap Id Value
-> Result Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
HashMap Id (Exp Delta)
-> HashMap Id Term
-> Exp Delta
-> HashMap Id Value
-> Result Builder
Eval.render
(Template -> HashMap Id (Exp Delta)
_tmplIncl Template
t HashMap Id (Exp Delta)
-> HashMap Id (Exp Delta) -> HashMap Id (Exp Delta)
forall a. Semigroup a => a -> a -> a
<> Template -> HashMap Id (Exp Delta)
_tmplExtends Template
t)
HashMap Id Term
fs
(Template -> Exp Delta
_tmplExp Template
t)
eitherParse :: ByteString -> Either String Template
eitherParse :: ByteString -> Either FilePath Template
eitherParse = Result Template -> Either FilePath Template
forall a. Result a -> Either FilePath a
eitherResult (Result Template -> Either FilePath Template)
-> (ByteString -> Result Template)
-> ByteString
-> Either FilePath Template
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Result Template
parse
eitherParseFile :: FilePath -> IO (Either String Template)
eitherParseFile :: FilePath -> IO (Either FilePath Template)
eitherParseFile = (Result Template -> Either FilePath Template)
-> IO (Result Template) -> IO (Either FilePath Template)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Result Template -> Either FilePath Template
forall a. Result a -> Either FilePath a
eitherResult (IO (Result Template) -> IO (Either FilePath Template))
-> (FilePath -> IO (Result Template))
-> FilePath
-> IO (Either FilePath Template)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO (Result Template)
parseFile
eitherParseWith ::
(Functor m, Monad m) =>
Syntax ->
Resolver m ->
Text ->
ByteString ->
m (Either String Template)
eitherParseWith :: forall (m :: * -> *).
(Functor m, Monad m) =>
Syntax
-> Resolver m -> Id -> ByteString -> m (Either FilePath Template)
eitherParseWith Syntax
o Resolver m
f Id
n = (Result Template -> Either FilePath Template)
-> m (Result Template) -> m (Either FilePath Template)
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Result Template -> Either FilePath Template
forall a. Result a -> Either FilePath a
eitherResult (m (Result Template) -> m (Either FilePath Template))
-> (ByteString -> m (Result Template))
-> ByteString
-> m (Either FilePath Template)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Syntax -> Resolver m -> Id -> ByteString -> m (Result Template)
forall (m :: * -> *).
Monad m =>
Syntax -> Resolver m -> Id -> ByteString -> m (Result Template)
parseWith Syntax
o Resolver m
f Id
n
eitherRender ::
Template ->
HashMap Text Value ->
Either String Text.Lazy.Text
eitherRender :: Template -> HashMap Id Value -> Either FilePath Text
eitherRender Template
t = Result Text -> Either FilePath Text
forall a. Result a -> Either FilePath a
eitherResult (Result Text -> Either FilePath Text)
-> (HashMap Id Value -> Result Text)
-> HashMap Id Value
-> Either FilePath Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Template -> HashMap Id Value -> Result Text
render Template
t
eitherRenderWith ::
HashMap Id Term ->
Template ->
HashMap Text Value ->
Either String Text.Lazy.Text
eitherRenderWith :: HashMap Id Term
-> Template -> HashMap Id Value -> Either FilePath Text
eitherRenderWith HashMap Id Term
fs Template
t = Result Text -> Either FilePath Text
forall a. Result a -> Either FilePath a
eitherResult (Result Text -> Either FilePath Text)
-> (HashMap Id Value -> Result Text)
-> HashMap Id Value
-> Either FilePath Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Id Term -> Template -> HashMap Id Value -> Result Text
renderWith HashMap Id Term
fs Template
t