@@ -1,4 +1,6 @@
1{-# LANGUAGE FlexibleInstances #-}
1{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE OverloadedStrings #-}
2-- | NOTE: This module is a highly experimental preview release. It may change
4-- | NOTE: This module is a highly experimental preview release. It may change
3-- drastically, or be entirely removed, in a future release.
5-- drastically, or be entirely removed, in a future release.
4module Data.Yaml.Builder
6module Data.Yaml.Builder
@@ -7,6 +9,10 @@ module Data.Yaml.Builder
10 , toByteString
16 , toByteString
11 , writeYamlFile
17 , writeYamlFile
@@ -16,11 +22,24 @@ import Data.Conduit
16import Data.ByteString (ByteString)
22import Data.ByteString (ByteString)
17import Text.Libyaml
23import Text.Libyaml
18import Data.Text (Text)
24import Data.Text (Text)
25+import Data.Scientific (Scientific)
26+import Data.Aeson.Types (Value(..))
27+import qualified Data.HashSet as HashSet
28+import qualified Data.Text as T
19import Data.Text.Encoding (encodeUtf8)
29import Data.Text.Encoding (encodeUtf8)
20import System.IO.Unsafe (unsafePerformIO)
30import System.IO.Unsafe (unsafePerformIO)
21import Control.Arrow (second)
31import Control.Arrow (second)
22import qualified Data.ByteString.Char8 as S8
32import qualified Data.ByteString.Char8 as S8
23import Control.Monad.Trans.Resource (runResourceT)
33import Control.Monad.Trans.Resource (runResourceT)
34+#if MIN_VERSION_aeson(0, 7, 0)
35+import qualified Data.Text.Encoding as TE
36+import qualified Data.Text.Lazy as TL
37+import Data.Text.Lazy.Builder (toLazyText)
38+import Data.Aeson.Encode (encodeToTextBuilder)
40+import qualified Data.ByteString.Char8 as S8
42+import Prelude hiding (null)
25(.=) :: ToYaml a => Text -> a -> (Text, YamlBuilder)
44(.=) :: ToYaml a => Text -> a -> (Text, YamlBuilder)
26k .= v = (k, toYaml v)
45k .= v = (k, toYaml v)
@@ -55,7 +74,54 @@ array bs =
55 go (YamlBuilder b) rest = b rest
74 go (YamlBuilder b) rest = b rest
57string :: Text -> YamlBuilder
76string :: Text -> YamlBuilder
77+-- Empty strings need special handling to ensure they get quoted. This avoids:
78+-- https://github.com/snoyberg/yaml/issues/24
79+string "" = YamlBuilder (EventScalar "" NoTag SingleQuoted Nothing :)
81+ YamlBuilder (event :)
84+ -- Make sure that special strings are encoded as strings properly.
85+ -- See: https://github.com/snoyberg/yaml/issues/31
86+ | s `HashSet.member` specialStrings || isNumeric s = EventScalar (encodeUtf8 s) NoTag SingleQuoted Nothing
58−string t = YamlBuilder (EventScalar (encodeUtf8 t) StrTag PlainNoTag Nothing:)
87+ | otherwise = EventScalar (encodeUtf8 s) StrTag PlainNoTag Nothing
89+ -- | Strings which must be escaped so as not to be treated as non-string scalars.
90+ specialStrings :: HashSet.HashSet Text
91+ specialStrings = HashSet.fromList $ T.words
92+ "y Y yes Yes YES n N no No NO true True TRUE false False FALSE on On ON off Off OFF null Null NULL ~"
94+ isNumeric :: Text -> Bool
98+ isNumeric' c = ('0' <= c && c <= '9')
106+-- Use aeson's implementation which gets rid of annoying decimal points
107+scientific :: Scientific -> YamlBuilder
108+scientific n = YamlBuilder (EventScalar (TE.encodeUtf8 $ TL.toStrict $ toLazyText $ encodeToTextBuilder (Number n)) IntTag PlainNoTag Nothing :)
110+{-# DEPRECATED number "Use scientific" #-}
111+#if MIN_VERSION_aeson(0,7,0)
112+number :: Scientific -> YamlBuilder
115+number :: Number -> YamlBuilder
116+number n rest = YamlBuilder (EventScalar (S8.pack $ show n) IntTag PlainNoTag Nothing :)
119+bool :: Bool -> YamlBuilder
120+bool True = YamlBuilder (EventScalar "true" BoolTag PlainNoTag Nothing :)
121+bool False = YamlBuilder (EventScalar "false" BoolTag PlainNoTag Nothing :)
124+null = YamlBuilder (EventScalar "null" NullTag PlainNoTag Nothing :)
60toEvents :: YamlBuilder -> [Event]
126toEvents :: YamlBuilder -> [Event]
61toEvents (YamlBuilder front) =
127toEvents (YamlBuilder front) =