content: {-# LANGUAGE CPP #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  -- | Provides a high-level interface for processing YAML files.
  --
  -- This module reuses most of the infrastructure from the @aeson@ package.
  -- This means that you can use all of the existing tools for JSON
  -- processing for processing YAML files. As a result, much of the
  -- documentation below mentions JSON; do not let that confuse you, it's
  -- intentional.
  --
  -- For the most part, YAML content translates directly into JSON, and
  -- therefore there is very little data loss. If you need to deal with YAML
  -- more directly (e.g., directly deal with aliases), you should use the
  -- "Text.Libyaml" module instead.
  --
  -- For documentation on the @aeson@ types, functions, classes, and
  -- operators, please see the @Data.Aeson@ module of the @aeson@ package.
  --
  -- Look in the examples directory of the source repository for some initial
  -- pointers on how to use this library.
  
  #if (defined (ghcjs_HOST_OS))
  module Data.Yaml {-# WARNING "GHCJS is not supported yet (will break at runtime once called)." #-}
  #else
  module Data.Yaml
  #endif
      ( -- * Encoding
        encode
      , encodeWith
      , encodeFile
      , encodeFileWith
        -- * Decoding
      , decodeEither'
      , decodeFileEither
      , decodeFileWithWarnings
      , decodeThrow
      , decodeFileThrow
        -- ** Decoding multiple documents
        --
        -- | For situations where we need to be able to parse multiple documents
        -- separated by `---` in a YAML stream, these functions decode a list of
        -- values rather than a single value.
      , decodeAllEither'
      , decodeAllFileEither
      , decodeAllFileWithWarnings
      , decodeAllThrow
      , decodeAllFileThrow
        -- ** More control over decoding
      , decodeHelper
        -- * Types
      , Value (..)
      , Parser
      , Object
      , Array
      , ParseException(..)
      , prettyPrintParseException
      , YamlException (..)
      , YamlMark (..)
        -- * Constructors and accessors
      , object
      , array
      , (.=)
      , (.:)
      , (.:?)
      , (.!=)
        -- ** With helpers (since 0.8.23)
      , withObject
      , withText
      , withArray
      , withScientific
      , withBool
        -- * Parsing
      , parseMonad
      , parseEither
      , parseMaybe
        -- * Classes
      , ToJSON (..)
      , FromJSON (..)
        -- * Custom encoding
      , isSpecialString
      , EncodeOptions
      , defaultEncodeOptions
      , defaultStringStyle
      , setStringStyle
      , setFormat
      , FormatOptions
      , defaultFormatOptions
      , setWidth
        -- * Deprecated
      , decode
      , decodeFile
      , decodeEither
      ) where
  #if !MIN_VERSION_base(4,8,0)
  import Control.Applicative((<$>))
  #endif
  import Control.Exception
  import Control.Monad.IO.Class (MonadIO, liftIO)
  import Control.Monad.Trans.Resource (MonadThrow, throwM)
  import Data.Aeson
      ( Value (..), ToJSON (..), FromJSON (..), object
      , (.=) , (.:) , (.:?) , (.!=)
      , Object, Array
      , withObject, withText, withArray, withScientific, withBool
      )
  import Data.Aeson.Types (parseMaybe, parseEither, Parser)
  import Data.ByteString (ByteString)
  import Data.Conduit ((.|), runConduitRes)
  import qualified Data.Conduit.List as CL
  import qualified Data.Vector as V
  import System.IO.Unsafe (unsafePerformIO)
  import Data.Text (Text)
  
  import Data.Yaml.Internal
  import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile, encodeWith, encodeFileWith)
  import qualified Text.Libyaml as Y
  
  -- | Set the string style in the encoded YAML. This is a function that decides
  -- for each string the type of YAML string to output.
  --
  -- __WARNING__: You must ensure that special strings (like @"yes"@\/@"no"@\/@"null"@\/@"1234"@) are not encoded with the 'Plain' style, because
  -- then they will be decoded as boolean, null or numeric values. You can use 'isSpecialString' to detect them.
  --
  -- By default, strings are encoded as follows:
  --
  -- * Any string containing a newline character uses the 'Literal' style
  --
  -- * Otherwise, any special string (see 'isSpecialString') uses 'SingleQuoted'
  --
  -- * Otherwise, use 'Plain'
  --
  -- @since 0.10.2.0
  setStringStyle :: (Text -> ( Tag, Style )) -> EncodeOptions -> EncodeOptions
  setStringStyle s opts = opts { encodeOptionsStringStyle = s }
  
  -- | Set the encoding formatting for the encoded YAML. By default, this is `defaultFormatOptions`.
  --
  -- @since 0.10.2.0
  setFormat :: FormatOptions -> EncodeOptions -> EncodeOptions
  setFormat f opts = opts { encodeOptionsFormat = f }
  
  -- |
  -- @since 0.10.2.0
  data EncodeOptions = EncodeOptions
    { encodeOptionsStringStyle :: Text -> ( Tag, Style )
    , encodeOptionsFormat :: FormatOptions
    }
  
  -- |
  -- @since 0.10.2.0
  defaultEncodeOptions :: EncodeOptions
  defaultEncodeOptions = EncodeOptions
    { encodeOptionsStringStyle = defaultStringStyle
    , encodeOptionsFormat = defaultFormatOptions
    }
  
  -- | Encode a value into its YAML representation.
  encode :: ToJSON a => a -> ByteString
  encode = encodeWith defaultEncodeOptions
  
  -- | Encode a value into its YAML representation with custom styling.
  --
  -- @since 0.10.2.0
  encodeWith :: ToJSON a => EncodeOptions -> a -> ByteString
  encodeWith opts obj = unsafePerformIO $ runConduitRes
      $ CL.sourceList (objToStream (encodeOptionsStringStyle opts) $ toJSON obj)
     .| Y.encodeWith (encodeOptionsFormat opts)
  
  -- | Encode a value into its YAML representation and save to the given file.
  encodeFile :: ToJSON a => FilePath -> a -> IO ()
  encodeFile = encodeFileWith defaultEncodeOptions
  
  -- | Encode a value into its YAML representation with custom styling and save to the given file.
  --
  -- @since 0.10.2.0
  encodeFileWith :: ToJSON a => EncodeOptions -> FilePath -> a -> IO ()
  encodeFileWith opts fp obj = runConduitRes
      $ CL.sourceList (objToStream (encodeOptionsStringStyle opts) $ toJSON obj)
     .| Y.encodeFileWith (encodeOptionsFormat opts) fp
  
  decode :: FromJSON a
         => ByteString
         -> Maybe a
  decode bs = unsafePerformIO
            $ either (const Nothing) snd
            <$> decodeHelper_ (Y.decode bs)
  {-# DEPRECATED decode "Please use decodeEither or decodeThrow, which provide information on how the decode failed" #-}
  
  decodeFile :: FromJSON a
             => FilePath
             -> IO (Maybe a)
  decodeFile fp = (fmap snd <$> decodeHelper (Y.decodeFile fp)) >>= either throwIO (return . either (const Nothing) id)
  {-# DEPRECATED decodeFile "Please use decodeFileEither, which does not confused type-directed and runtime exceptions." #-}
  
  -- | A version of 'decodeFile' which should not throw runtime exceptions.
  --
  -- @since 0.8.4
  decodeFileEither
      :: FromJSON a
      => FilePath
      -> IO (Either ParseException a)
  decodeFileEither = fmap (fmap snd) . decodeFileWithWarnings
  
  -- | Like `decodeFileEither`, but decode multiple documents.
  --
  -- @since 0.11.5.0
  decodeAllFileEither
      :: FromJSON a
      => FilePath
      -> IO (Either ParseException [a])
  decodeAllFileEither = fmap (fmap snd) . decodeAllFileWithWarnings
  
  -- | A version of `decodeFileEither` that returns warnings along with the parse
  -- result.
  --
  -- @since 0.10.0
  decodeFileWithWarnings
      :: FromJSON a
      => FilePath
      -> IO (Either ParseException ([Warning], a))
  decodeFileWithWarnings = decodeHelper_ . Y.decodeFile
  
  -- | Like `decodeFileWithWarnings`, but decode multiple documents.
  --
  -- @since 0.11.5.0
  decodeAllFileWithWarnings
      :: FromJSON a
      => FilePath
      -> IO (Either ParseException ([Warning], [a]))
  decodeAllFileWithWarnings = decodeAllHelper_ . Y.decodeFile
  
  decodeEither :: FromJSON a => ByteString -> Either String a
  decodeEither bs = unsafePerformIO
                  $ either (Left . prettyPrintParseException) id
                  <$> (fmap snd <$> decodeHelper (Y.decode bs))
  {-# DEPRECATED decodeEither "Please use decodeEither' or decodeThrow, which provide more useful failures" #-}
  
  -- | More helpful version of 'decodeEither' which returns the 'YamlException'.
  --
  -- @since 0.8.3
  decodeEither' :: FromJSON a => ByteString -> Either ParseException a
  decodeEither' = either Left (either (Left . AesonException) Right)
                . unsafePerformIO
                . fmap (fmap snd) . decodeHelper
                . Y.decode
  
  -- | Like 'decodeEither'', but decode multiple documents.
  --
  -- @since 0.11.5.0
  decodeAllEither' :: FromJSON a => ByteString -> Either ParseException [a]
  decodeAllEither' = either Left (either (Left . AesonException) Right)
                   . unsafePerformIO
                   . fmap (fmap snd) . decodeAllHelper
                   . Y.decode
  
  -- | A version of 'decodeEither'' lifted to MonadThrow
  --
  -- @since 0.8.31
  decodeThrow :: (MonadThrow m, FromJSON a) => ByteString -> m a
  decodeThrow = either throwM return . decodeEither'
  
  -- | Like `decodeThrow`, but decode multiple documents.
  --
  -- @since 0.11.5.0
  decodeAllThrow :: (MonadThrow m, FromJSON a) => ByteString -> m [a]
  decodeAllThrow = either throwM return . decodeAllEither'
  
  -- | A version of 'decodeFileEither' lifted to MonadIO
  --
  -- @since 0.8.31
  decodeFileThrow :: (MonadIO m, FromJSON a) => FilePath -> m a
  decodeFileThrow f = liftIO $ decodeFileEither f >>= either throwIO return
  
  -- | Like `decodeFileThrow`, but decode multiple documents.
  --
  -- @since 0.11.5.0
  decodeAllFileThrow :: (MonadIO m, FromJSON a) => FilePath -> m [a]
  decodeAllFileThrow f = liftIO $ decodeAllFileEither f >>= either throwIO return
  
  -- | Construct a new 'Value' from a list of 'Value's.
  array :: [Value] -> Value
  array = Array . V.fromList
  
  #if MIN_VERSION_base(4, 13, 0)
  parseMonad :: MonadFail m => (a -> Parser b) -> a -> m b
  #else
  parseMonad :: Monad m => (a -> Parser b) -> a -> m b
  #endif
  parseMonad p = either fail return . parseEither p
  {-# DEPRECATED parseMonad "With the MonadFail split, this function is going to be removed in the future. Please migrate to parseEither." #-}
  