2{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE OverloadedStrings #-}
5-- | Provides a high-level interface for processing YAML files.
7-- This module reuses most of the infrastructure from the @aeson@ package.
8-- This means that you can use all of the existing tools for JSON
9-- processing for processing YAML files. As a result, much of the
10-- documentation below mentions JSON; do not let that confuse you, it's
13-- For the most part, YAML content translates directly into JSON, and
14-- therefore there is very little data loss. If you need to deal with YAML
15-- more directly (e.g., directly deal with aliases), you should use the
16-- "Text.Libyaml" module instead.
18-- For documentation on the @aeson@ types, functions, classes, and
19-- operators, please see the @Data.Aeson@ module of the @aeson@ package.
21-- Look in the examples directory of the source repository for some initial
22-- pointers on how to use this library.
24#if (defined (ghcjs_HOST_OS))
25module Data.Yaml {-# WARNING "GHCJS is not supported yet (will break at runtime once called)." #-}
35 , prettyPrintParseException
38 -- * Constructors and accessors
52 -- * Encoding/decoding
57 -- ** Better error information
61 -- ** More control over decoding
64#if !MIN_VERSION_base(4,8,0)
65import Control.Applicative((<$>))
67import Control.Exception
68import Control.Monad.Trans.Resource (runResourceT)
70 ( Value (..), ToJSON (..), FromJSON (..), object
71 , (.=) , (.:) , (.:?) , (.!=)
74import Data.Aeson.Encode (encodeToTextBuilder)
75import Data.Aeson.Types (Pair, parseMaybe, parseEither, Parser)
76import Data.ByteString (ByteString)
77import qualified Data.Conduit as C
78import qualified Data.Conduit.List as CL
79import qualified Data.HashMap.Strict as M
80import qualified Data.HashSet as HashSet
81import Data.Text.Encoding (encodeUtf8)
82import qualified Data.Text.Encoding as TE
83import qualified Data.Text.Lazy as TL
84import Data.Text.Lazy.Builder (toLazyText)
85import qualified Data.Vector as V
86import System.IO.Unsafe (unsafePerformIO)
88import Data.Yaml.Internal
89import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile)
90import qualified Text.Libyaml as Y
92encode :: ToJSON a => a -> ByteString
93encode obj = unsafePerformIO $
94 runResourceT $ CL.sourceList (objToEvents $ toJSON obj)
97encodeFile :: ToJSON a => FilePath -> a -> IO ()
98encodeFile fp obj = runResourceT
99 $ CL.sourceList (objToEvents $ toJSON obj)
102objToEvents :: Value -> [Y.Event]
103objToEvents o = (:) EventStreamStart
104 . (:) EventDocumentStart
111scalarToEvent :: YamlScalar -> Event
112scalarToEvent (YamlScalar v t s) = EventScalar v t s Nothing
115objToEvents' :: Value -> [Y.Event] -> [Y.Event]
116--objToEvents' (Scalar s) rest = scalarToEvent s : rest
117objToEvents' (Array list) rest =
118 EventSequenceStart Nothing
119 : foldr objToEvents' (EventSequenceEnd : rest) (V.toList list)
120objToEvents' (Object pairs) rest =
121 EventMappingStart Nothing
122 : foldr pairToEvents (EventMappingEnd : rest) (M.toList pairs)
124-- Empty strings need special handling to ensure they get quoted. This avoids:
125-- https://github.com/snoyberg/yaml/issues/24
126objToEvents' (String "") rest = EventScalar "" NoTag SingleQuoted Nothing : rest
128objToEvents' (String s) rest =
132 -- Make sure that special strings are encoded as strings properly.
133 -- See: https://github.com/snoyberg/yaml/issues/31
134 | s `HashSet.member` specialStrings || isNumeric s = EventScalar (encodeUtf8 s) NoTag SingleQuoted Nothing
135 | otherwise = EventScalar (encodeUtf8 s) StrTag PlainNoTag Nothing
136objToEvents' Null rest = EventScalar "null" NullTag PlainNoTag Nothing : rest
137objToEvents' (Bool True) rest = EventScalar "true" BoolTag PlainNoTag Nothing : rest
138objToEvents' (Bool False) rest = EventScalar "false" BoolTag PlainNoTag Nothing : rest
139-- Use aeson's implementation which gets rid of annoying decimal points
140objToEvents' n@Number{} rest = EventScalar (TE.encodeUtf8 $ TL.toStrict $ toLazyText $ encodeToTextBuilder n) IntTag PlainNoTag Nothing : rest
142pairToEvents :: Pair -> [Y.Event] -> [Y.Event]
143pairToEvents (k, v) rest =
144 EventScalar (encodeUtf8 k) StrTag PlainNoTag Nothing
145 : objToEvents' v rest
150decode bs = unsafePerformIO
151 $ either (const Nothing) id
152 <$> decodeHelper_ (Y.decode bs)
154decodeFile :: FromJSON a
157decodeFile fp = decodeHelper (Y.decodeFile fp) >>= either throwIO (return . either (const Nothing) id)
159-- | A version of 'decodeFile' which should not throw runtime exceptions.
165 -> IO (Either ParseException a)
166decodeFileEither = decodeHelper_ . Y.decodeFile
168decodeEither :: FromJSON a => ByteString -> Either String a
169decodeEither bs = unsafePerformIO
170 $ either (Left . prettyPrintParseException) id
171 <$> decodeHelper (Y.decode bs)
173-- | More helpful version of 'decodeEither' which returns the 'YamlException'.
176decodeEither' :: FromJSON a => ByteString -> Either ParseException a
177decodeEither' = either Left (either (Left . AesonException) Right)
182array :: [Value] -> Value
183array = Array . V.fromList
185parseMonad :: Monad m => (a -> Parser b) -> a -> m b
186parseMonad p = either fail return . parseEither p
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list