module Yamlet
(
decode
, decodeAll
, decodeText
, decodeAllText
, decodeInput
, decodeFile
, decodeAllFile
, decodeWithDocument
, decodeDocument
, decodeDocuments
, encode
, encodeAll
, encodeText
, encodeAllText
, encodeFile
, encodeAllFile
, S.Node
, S.Offset (..)
, S.noOffset
, S.Located (..)
, S.Commented (..)
, S.Comments (..)
, S.noComments
, S.Line (..)
, module Yamlet.Value
, module Yamlet.Decode
, module Yamlet.Encode
, module Yamlet.Generic
, module Yamlet.Error
) where
import Control.Monad
import Data.Bifunctor
import Data.ByteString qualified as BS
import Data.List.NonEmpty qualified as NE
import Data.Maybe
import Data.Text qualified as T
import Data.Text.Encoding qualified as T
import Yamlet.Decode
import Yamlet.Encode
import Yamlet.Error
import Yamlet.Generic
import Yamlet.Internal.Compose
import Yamlet.Internal.Encoder
import Yamlet.Internal.FromYaml
import Yamlet.Internal.Input
import Yamlet.Internal.Parser
import Yamlet.Internal.Syntax qualified as S
import Yamlet.Internal.Utils
import Yamlet.Value
decode :: FromYaml a => BS.ByteString -> Either (NE.NonEmpty Error) a
decode :: forall a. FromYaml a => ByteString -> Either (NonEmpty Error) a
decode ByteString
bs = Either Error Text -> Either (NonEmpty Error) Text
forall a. Either Error a -> Either (NonEmpty Error) a
single (ByteString -> Either Error Text
decodeInput ByteString
bs) Either (NonEmpty Error) Text
-> (Text -> Either (NonEmpty Error) a) -> Either (NonEmpty Error) a
forall a b.
Either (NonEmpty Error) a
-> (a -> Either (NonEmpty Error) b) -> Either (NonEmpty Error) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> Either (NonEmpty Error) a
forall a. FromYaml a => Text -> Either (NonEmpty Error) a
decodeText
decodeAll :: FromYaml a => BS.ByteString -> Either (NE.NonEmpty Error) [a]
decodeAll :: forall a. FromYaml a => ByteString -> Either (NonEmpty Error) [a]
decodeAll ByteString
bs = Either Error Text -> Either (NonEmpty Error) Text
forall a. Either Error a -> Either (NonEmpty Error) a
single (ByteString -> Either Error Text
decodeInput ByteString
bs) Either (NonEmpty Error) Text
-> (Text -> Either (NonEmpty Error) [a])
-> Either (NonEmpty Error) [a]
forall a b.
Either (NonEmpty Error) a
-> (a -> Either (NonEmpty Error) b) -> Either (NonEmpty Error) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> Either (NonEmpty Error) [a]
forall a. FromYaml a => Text -> Either (NonEmpty Error) [a]
decodeAllText
decodeText :: FromYaml a => T.Text -> Either (NE.NonEmpty Error) a
decodeText :: forall a. FromYaml a => Text -> Either (NonEmpty Error) a
decodeText Text
input = do
(a, _) <- Text -> Either (NonEmpty Error) (a, Document)
forall a.
FromYaml a =>
Text -> Either (NonEmpty Error) (a, Document)
decodeWithDocument Text
input
pure a
decodeWithDocument :: FromYaml a => T.Text -> Either (NE.NonEmpty Error) (a, S.Document)
decodeWithDocument :: forall a.
FromYaml a =>
Text -> Either (NonEmpty Error) (a, Document)
decodeWithDocument Text
input =
Either Error [Document] -> Either (NonEmpty Error) [Document]
forall a. Either Error a -> Either (NonEmpty Error) a
single (Text -> Either Error [Document]
parseStream Text
input) Either (NonEmpty Error) [Document]
-> ([Document] -> Either (NonEmpty Error) (a, Document))
-> Either (NonEmpty Error) (a, Document)
forall a b.
Either (NonEmpty Error) a
-> (a -> Either (NonEmpty Error) b) -> Either (NonEmpty Error) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
[] ->
Document -> Either (NonEmpty Error) (a, Document)
forall a.
FromYaml a =>
Document -> Either (NonEmpty Error) (a, Document)
withDocument (Document -> Either (NonEmpty Error) (a, Document))
-> (Node -> Document)
-> Node
-> Either (NonEmpty Error) (a, Document)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Node -> Document
S.document (Node -> Either (NonEmpty Error) (a, Document))
-> Node -> Either (NonEmpty Error) (a, Document)
forall a b. (a -> b) -> a -> b
$
S.Node
{ offset :: Offset
S.offset = Int -> Offset
S.Offset Int
0
, endOffset :: Offset
S.endOffset = Int -> Offset
S.Offset Int
0
, props :: Props
S.props = Props
S.noProps
, comments :: Comments
S.comments = Comments
S.noComments
, content :: Content
S.content = ScalarStyle -> Text -> Content
S.ScalarContent ScalarStyle
S.Plain Text
""
}
[Document
doc] -> Document -> Either (NonEmpty Error) (a, Document)
forall a.
FromYaml a =>
Document -> Either (NonEmpty Error) (a, Document)
withDocument Document
doc
docs :: [Document]
docs@(Document
_ : Document
doc : [Document]
_) -> do
let limit :: Int
limit = [Node] -> Int
aliasLimit ((Document -> Node) -> [Document] -> [Node]
forall a b. (a -> b) -> [a] -> [b]
map (.root) [Document]
docs)
check :: Int -> S.Document -> Either (NE.NonEmpty Error) Int
check :: Int -> Document -> Either (NonEmpty Error) Int
check Int
added Document
d =
(Node, Int) -> Int
forall a b. (a, b) -> b
snd ((Node, Int) -> Int)
-> Either (NonEmpty Error) (Node, Int)
-> Either (NonEmpty Error) Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (NonEmpty (Offset, String) -> NonEmpty Error)
-> Either (NonEmpty (Offset, String)) (Node, Int)
-> Either (NonEmpty Error) (Node, Int)
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Text -> Document -> NonEmpty (Offset, String) -> NonEmpty Error
decoderErrors Text
input Document
d) (Int
-> Int -> Node -> Either (NonEmpty (Offset, String)) (Node, Int)
prepareWithin Int
limit Int
added Document
d.root)
(Int -> Document -> Either (NonEmpty Error) Int)
-> Int -> [Document] -> Either (NonEmpty Error) ()
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m ()
foldM_ Int -> Document -> Either (NonEmpty Error) Int
check Int
0 [Document]
docs
Either Error (a, Document) -> Either (NonEmpty Error) (a, Document)
forall a. Either Error a -> Either (NonEmpty Error) a
single (Either Error (a, Document)
-> Either (NonEmpty Error) (a, Document))
-> (Error -> Either Error (a, Document))
-> Error
-> Either (NonEmpty Error) (a, Document)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Error -> Either Error (a, Document)
forall a b. a -> Either a b
Left (Error -> Either (NonEmpty Error) (a, Document))
-> Error -> Either (NonEmpty Error) (a, Document)
forall a b. (a -> b) -> a -> b
$
Text -> Offset -> String -> Error
errorAt Text
input Document
doc.root.offset String
"expected a single document, but got a second one"
where
withDocument :: FromYaml a => S.Document -> Either (NE.NonEmpty Error) (a, S.Document)
withDocument :: forall a.
FromYaml a =>
Document -> Either (NonEmpty Error) (a, Document)
withDocument Document
doc = do
a <- Text -> Document -> Either (NonEmpty Error) a
forall a.
FromYaml a =>
Text -> Document -> Either (NonEmpty Error) a
decodeDocument Text
input Document
doc
pure (a, doc)
decodeAllText :: FromYaml a => T.Text -> Either (NE.NonEmpty Error) [a]
decodeAllText :: forall a. FromYaml a => Text -> Either (NonEmpty Error) [a]
decodeAllText Text
input = Either Error [Document] -> Either (NonEmpty Error) [Document]
forall a. Either Error a -> Either (NonEmpty Error) a
single (Text -> Either Error [Document]
parseStream Text
input) Either (NonEmpty Error) [Document]
-> ([Document] -> Either (NonEmpty Error) [a])
-> Either (NonEmpty Error) [a]
forall a b.
Either (NonEmpty Error) a
-> (a -> Either (NonEmpty Error) b) -> Either (NonEmpty Error) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> [Document] -> Either (NonEmpty Error) [a]
forall a.
FromYaml a =>
Text -> [Document] -> Either (NonEmpty Error) [a]
decodeDocuments Text
input
single :: Either Error a -> Either (NE.NonEmpty Error) a
single :: forall a. Either Error a -> Either (NonEmpty Error) a
single = (Error -> NonEmpty Error)
-> Either Error a -> Either (NonEmpty Error) a
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Error -> [Error] -> NonEmpty Error
forall a. a -> [a] -> NonEmpty a
NE.:| [])
decodeDocument :: FromYaml a => T.Text -> S.Document -> Either (NE.NonEmpty Error) a
decodeDocument :: forall a.
FromYaml a =>
Text -> Document -> Either (NonEmpty Error) a
decodeDocument Text
input Document
doc =
Either (NonEmpty Error) (a, Int) -> Either (NonEmpty Error) a
forall e a b. Either e (a, b) -> Either e a
firstOfResult (Either (NonEmpty Error) (a, Int) -> Either (NonEmpty Error) a)
-> Either (NonEmpty Error) (a, Int) -> Either (NonEmpty Error) a
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Text -> Document -> Either (NonEmpty Error) (a, Int)
forall a.
FromYaml a =>
Int -> Int -> Text -> Document -> Either (NonEmpty Error) (a, Int)
decodeDocumentWithin ([Node] -> Int
aliasLimit [Document
doc.root]) Int
0 Text
input Document
doc
decodeDocuments :: FromYaml a => T.Text -> [S.Document] -> Either (NE.NonEmpty Error) [a]
decodeDocuments :: forall a.
FromYaml a =>
Text -> [Document] -> Either (NonEmpty Error) [a]
decodeDocuments Text
input [Document]
docs = Int -> [Document] -> Either (NonEmpty Error) [a]
forall a.
FromYaml a =>
Int -> [Document] -> Either (NonEmpty Error) [a]
go Int
0 [Document]
docs
where
limit :: Int
limit :: Int
limit = [Node] -> Int
aliasLimit ((Document -> Node) -> [Document] -> [Node]
forall a b. (a -> b) -> [a] -> [b]
map (.root) [Document]
docs)
go :: FromYaml a => Int -> [S.Document] -> Either (NE.NonEmpty Error) [a]
go :: forall a.
FromYaml a =>
Int -> [Document] -> Either (NonEmpty Error) [a]
go Int
added = \case
[] -> [a] -> Either (NonEmpty Error) [a]
forall a b. b -> Either a b
Right []
Document
d : [Document]
ds -> do
(a, added') <- Int -> Int -> Text -> Document -> Either (NonEmpty Error) (a, Int)
forall a.
FromYaml a =>
Int -> Int -> Text -> Document -> Either (NonEmpty Error) (a, Int)
decodeDocumentWithin Int
limit Int
added Text
input Document
d
(a :) <$> go added' ds
decodeDocumentWithin
:: FromYaml a
=> Int -> Int -> T.Text -> S.Document -> Either (NE.NonEmpty Error) (a, Int)
decodeDocumentWithin :: forall a.
FromYaml a =>
Int -> Int -> Text -> Document -> Either (NonEmpty Error) (a, Int)
decodeDocumentWithin Int
limit Int
added Text
input Document
doc =
(NonEmpty (Offset, String) -> NonEmpty Error)
-> Either (NonEmpty (Offset, String)) (a, Int)
-> Either (NonEmpty Error) (a, Int)
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Text -> Document -> NonEmpty (Offset, String) -> NonEmpty Error
decoderErrors Text
input Document
doc) (Int
-> Int
-> (Node -> Parser a)
-> Node
-> Either (NonEmpty (Offset, String)) (a, Int)
forall a.
Int
-> Int
-> (Node -> Parser a)
-> Node
-> Either (NonEmpty (Offset, String)) (a, Int)
runParserWithin Int
limit Int
added Node -> Parser a
forall a. FromYaml a => Node -> Parser a
parseYaml Node
root)
where
root :: S.Node
root :: Node
root
| [Line] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Comments
dc.before Bool -> Bool -> Bool
&& Maybe Text -> Bool
forall a. Maybe a -> Bool
isNothing Comments
dc.inline Bool -> Bool -> Bool
&& [Line] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Comments
dc.after = Node
r
| Bool
otherwise = Comments -> Node -> Node
S.withComments Comments
comments Node
r
dc :: S.Comments
dc :: Comments
dc = Document
doc.docComments
r :: S.Node
r :: Node
r = Document
doc.root
comments :: S.Comments
comments :: Comments
comments =
S.Comments
{ before :: [Line]
S.before =
Comments
dc.before [Line] -> [Line] -> [Line]
forall a. [a] -> [a] -> [a]
++ [Text -> Line
S.Comment Text
c | Just Text
c <- [Comments
dc.inline]] [Line] -> [Line] -> [Line]
forall a. [a] -> [a] -> [a]
++ Node
r.comments.before
, inline :: Maybe Text
S.inline = Node
r.comments.inline
, after :: [Line]
S.after = Node
r.comments.after [Line] -> [Line] -> [Line]
forall a. [a] -> [a] -> [a]
++ Comments
dc.after
}
decoderErrors
:: T.Text -> S.Document -> NE.NonEmpty (S.Offset, String) -> NE.NonEmpty Error
decoderErrors :: Text -> Document -> NonEmpty (Offset, String) -> NonEmpty Error
decoderErrors Text
input Document
doc = [Error] -> NonEmpty Error
forall a. HasCallStack => [a] -> NonEmpty a
NE.fromList ([Error] -> NonEmpty Error)
-> (NonEmpty (Offset, String) -> [Error])
-> NonEmpty (Offset, String)
-> NonEmpty Error
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Document -> [(Offset, String)] -> [Error]
documentErrors Text
input Document
doc ([(Offset, String)] -> [Error])
-> (NonEmpty (Offset, String) -> [(Offset, String)])
-> NonEmpty (Offset, String)
-> [Error]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (Offset, String) -> [(Offset, String)]
forall a. NonEmpty a -> [a]
NE.toList
encode :: ToYaml a => a -> BS.ByteString
encode :: forall a. ToYaml a => a -> ByteString
encode = Text -> ByteString
T.encodeUtf8 (Text -> ByteString) -> (a -> Text) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Text
forall a. ToYaml a => a -> Text
encodeText
encodeAll :: ToYaml a => [a] -> BS.ByteString
encodeAll :: forall a. ToYaml a => [a] -> ByteString
encodeAll = Text -> ByteString
T.encodeUtf8 (Text -> ByteString) -> ([a] -> Text) -> [a] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Text
forall a. ToYaml a => [a] -> Text
encodeAllText
encodeText :: ToYaml a => a -> T.Text
encodeText :: forall a. ToYaml a => a -> Text
encodeText a
a = [Node] -> Text
renderDocuments [a -> Node
forall a. ToYaml a => a -> Node
toYaml a
a]
encodeAllText :: ToYaml a => [a] -> T.Text
encodeAllText :: forall a. ToYaml a => [a] -> Text
encodeAllText = [Node] -> Text
renderDocuments ([Node] -> Text) -> ([a] -> [Node]) -> [a] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Node) -> [a] -> [Node]
forall a b. (a -> b) -> [a] -> [b]
map a -> Node
forall a. ToYaml a => a -> Node
toYaml
decodeFile :: FromYaml a => FilePath -> IO (Either (NE.NonEmpty Error) a)
decodeFile :: forall a. FromYaml a => String -> IO (Either (NonEmpty Error) a)
decodeFile String
path = ByteString -> Either (NonEmpty Error) a
forall a. FromYaml a => ByteString -> Either (NonEmpty Error) a
decode (ByteString -> Either (NonEmpty Error) a)
-> IO ByteString -> IO (Either (NonEmpty Error) a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO ByteString
BS.readFile String
path
decodeAllFile :: FromYaml a => FilePath -> IO (Either (NE.NonEmpty Error) [a])
decodeAllFile :: forall a. FromYaml a => String -> IO (Either (NonEmpty Error) [a])
decodeAllFile String
path = ByteString -> Either (NonEmpty Error) [a]
forall a. FromYaml a => ByteString -> Either (NonEmpty Error) [a]
decodeAll (ByteString -> Either (NonEmpty Error) [a])
-> IO ByteString -> IO (Either (NonEmpty Error) [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO ByteString
BS.readFile String
path
encodeFile :: ToYaml a => FilePath -> a -> IO ()
encodeFile :: forall a. ToYaml a => String -> a -> IO ()
encodeFile String
path = String -> ByteString -> IO ()
BS.writeFile String
path (ByteString -> IO ()) -> (a -> ByteString) -> a -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ByteString
forall a. ToYaml a => a -> ByteString
encode
encodeAllFile :: ToYaml a => FilePath -> [a] -> IO ()
encodeAllFile :: forall a. ToYaml a => String -> [a] -> IO ()
encodeAllFile String
path = String -> ByteString -> IO ()
BS.writeFile String
path (ByteString -> IO ()) -> ([a] -> ByteString) -> [a] -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> ByteString
forall a. ToYaml a => [a] -> ByteString
encodeAll