yaml 0.11.5.0 → 0.11.11.2
raw patch · 11 files changed
Files
- ChangeLog.md +34/−0
- README.md +10/−2
- exe/Common.hs +68/−0
- exe/json2yaml.hs +101/−17
- exe/yaml2json.hs +79/−23
- src/Data/Yaml/Config.hs +24/−8
- src/Data/Yaml/Internal.hs +45/−12
- src/Data/Yaml/Pretty.hs +18/−2
- test/Data/Yaml/IncludeSpec.hs +5/−0
- test/Data/YamlSpec.hs +32/−5
- yaml.cabal +30/−36
ChangeLog.md view
@@ -1,5 +1,39 @@ # ChangeLog for yaml +## 0.11.11.2++* Compat with aeson 2.2++## 0.11.11.1++* For optparse-applicative-0.18: use `pretty` instead of `text` [#216](https://github.com/snoyberg/yaml/pull/216)++## 0.11.11.0++* Fix ambiguous occurrence `AesonException`++## 0.11.10.0++* Undo previous change (breakage with aeson 2)++## 0.11.9.0++* Data.Yaml.Pretty: provide key-sorting function with path to parent object [#206](https://github.com/snoyberg/yaml/pull/206)++## 0.11.8.0++* Export `Parse` and `StringStyle` [#204](https://github.com/snoyberg/yaml/pull/204)++## 0.11.7.0++* Support `aeson` 2 [#202](https://github.com/snoyberg/yaml/pull/202)++## 0.11.6.0++* `yaml2json`: add `--help` and `--version` options [#197](https://github.com/snoyberg/yaml/pull/197)+* `json2yaml`: add `--help` and `--version` options [#198](https://github.com/snoyberg/yaml/pull/198)+* Add the `-o` options to both `yaml2json` and `json2yaml` [#200](https://github.com/snoyberg/yaml/pull/200)+ ## 0.11.5.0 * New functions capable of parsing YAML streams containing multiple documents into a list of results:
README.md view
@@ -1,7 +1,7 @@ ## yaml -[](https://travis-ci.org/snoyberg/yaml)-[](https://ci.appveyor.com/project/snoyberg/yaml/branch/master)+[](https://github.com/snoyberg/yaml/actions/workflows/tests.yml)+[](https://ci.appveyor.com/project/snoyberg/yaml/branch/master) Provides support for parsing and emitting Yaml documents. @@ -16,3 +16,11 @@ * `Data.Yaml.Include` supports adding `!include` directives to your YAML files. * `Data.Yaml.Builder` and `Data.Yaml.Parser` allow more fine-grained control of parsing an rendering, as opposed to just using the aeson typeclass and datatype system for parsing and rendering. * `Data.Yaml.Aeson` is currently a re-export of `Data.Yaml` to explicitly choose to use the aeson-compatible API.++### Executables++Converters `json2yaml` and `yaml2json` can be built by disabling flag `no-exe`, e.g., one of:+```+cabal install yaml -f-no-exe+stack install yaml --flag yaml:-no-exe+```
+ exe/Common.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}++-- | Code shared between @yaml2json@ and @json2yaml@.++module Common where++import Data.List ( intercalate )+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup ( Semigroup(..) )+#endif+import Data.Version ( Version(versionBranch) )++import Options.Applicative ( Parser, help, hidden, infoOption, long, short )++import qualified Paths_yaml as Paths++-- * Version info and option+---------------------------------------------------------------------------++-- | Homepage for @yaml2json@ and @json2yaml@.++homepage :: String+homepage = "https://github.com/snoyberg/yaml/"++-- | Version in @x.y.z@ format.++version :: String+version = intercalate "." $ map show $ versionBranch Paths.version++-- | The version header including given program name and 'homepage'.++versionText :: String -> String+versionText self = unwords+ [ self+ , "version"+ , version+ , homepage -- concat [ "<", homepage, ">" ]+ ]++-- | Option @--numeric-version@.++numericVersionOption :: Parser (a -> a)+numericVersionOption =+ infoOption version+ $ long "numeric-version"+ <> hidden+ <> help "Show just version number."++-- | Option @--version@.++versionOption :: String -> Parser (a -> a)+versionOption self =+ infoOption (versionText self)+ $ long "version"+ <> short 'V'+ <> hidden+ <> help "Show version info."++-- * Misc+---------------------------------------------------------------------------++-- | @Just@ unless argument is @"-"@ (denoting @stdin@ or @stdout@).++dashToNothing :: FilePath -> Maybe FilePath+dashToNothing = \case+ "-" -> Nothing+ file -> Just file
exe/json2yaml.hs view
@@ -1,22 +1,106 @@-import qualified Data.Aeson as J-import qualified Data.ByteString as S+{-# LANGUAGE CPP #-}+{-# LANGUAGE NamedFieldPuns #-}++import qualified Data.Aeson as J+import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L-import System.Environment (getArgs)+import qualified Data.Yaml as Y+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup ( Semigroup(..) )+#endif -import qualified Data.Yaml as Y+import Options.Applicative+ ( Parser, (<|>)+ , action, execParser, footerDoc, headerDoc, help, helper, hidden, info+ , long, metavar, short, strArgument, strOption, value+ )+import Options.Applicative.Help.Pretty+ ( vcat, pretty ) +import System.Exit ( die )++import Common ( dashToNothing, versionText, versionOption, numericVersionOption )++data Options = Options+ { optInput :: Maybe FilePath+ -- ^ 'Nothing' means @stdin@.+ , optOutput :: Maybe FilePath+ -- ^ 'Nothing' means @stdout@.+ }++-- | Name of the executable.++self :: String+self = "json2yaml"++-- | Parse options; handle parse errors, @--help@, @--version@.++options :: IO Options+options =+ execParser $+ info (helper <*> versionOption self <*> numericVersionOption <*> programOptions)+ $ headerDoc hdoc+ <> footerDoc fdoc++ where+ hdoc = Just $ vcat $ map pretty+ [ versionText self+ , "Convert JSON to YAML."+ ]+ fdoc = Just $ pretty $ concat+ [ "The old call pattern '"+ , self+ , " IN OUT' is also accepted, but deprecated."+ ]++ programOptions :: Parser Options+ programOptions = Options <$> oInput <*> oOutput++ oInput :: Parser (Maybe FilePath)+ oInput = dashToNothing <$> do+ strArgument+ $ metavar "IN"+ <> value "-"+ <> action "file"+ <> help "The input file containing the JSON document; use '-' for stdin (default)."++ oOutput :: Parser (Maybe FilePath)+ oOutput = dashToNothing <$> do+ oOutputExplicit <|> oOutputImplicit++ oOutputExplicit :: Parser FilePath+ oOutputExplicit =+ strOption+ $ long "output"+ <> short 'o'+ <> metavar "OUT"+ <> action "file"+ -- <> help "The file to hold the produced YAML document; use '-' for stdout (default)."++ oOutputImplicit :: Parser FilePath+ oOutputImplicit =+ strArgument+ $ metavar "OUT"+ <> value "-"+ <> action "file"+ <> hidden+ <> help "The file to hold the produced YAML document; use '-' for stdout (default)."++-- | Exit with 'self'-stamped error message.++abort :: String -> IO a+abort msg = die $ concat [ self, ": ", msg ]+ main :: IO () main = do- args <- getArgs- (input, output) <- case args ++ replicate (2 - length args) "-" of- [i, o] -> return (i, o)- _ -> fail "Usage: json2yaml [in] [out]"- mval <- fmap J.decode $- case input of- "-" -> L.getContents- _ -> L.readFile input- case mval of- Nothing -> error "Invalid input JSON"- Just val -> case output of- "-" -> S.putStr $ Y.encode (val :: Y.Value)- _ -> Y.encodeFile output val+ Options{ optInput, optOutput } <- options++ -- Read JSON.+ mval <- J.decode <$> maybe L.getContents L.readFile optInput++ -- Write YAML.+ case mval of+ Nothing -> abort "Invalid input JSON"+ Just val -> case optOutput of+ Nothing -> S.putStr $ Y.encode (val :: Y.Value)+ Just f -> Y.encodeFile f val
exe/yaml2json.hs view
@@ -1,31 +1,87 @@-import Prelude hiding (putStr, getContents)+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-} -import Data.Aeson (encode, Value)-import Data.ByteString (getContents)-import Data.ByteString.Lazy (putStr)-import System.Environment (getArgs)-import System.Exit-import System.IO (stderr, hPutStrLn)+import Data.Aeson (encode, Value)+import qualified Data.ByteString as S (getContents)+import qualified Data.ByteString.Lazy as L (putStr, writeFile)+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup (Semigroup(..))+#endif+import Data.Yaml (decodeFileEither, decodeEither')+import System.Exit (die) -import Data.Yaml (decodeFileEither, decodeEither')+import Options.Applicative+ ( Parser+ , action, execParser, headerDoc, help, helper, info+ , long, metavar, short, strArgument, strOption, value+ )+import Options.Applicative.Help.Pretty+ ( vcat, pretty ) -helpMessage :: IO ()-helpMessage = putStrLn "Usage: yaml2json FILE\n\nuse '-' as FILE to indicate stdin" >> exitFailure+import Common+ ( versionText, versionOption, numericVersionOption, dashToNothing ) -showJSON :: Show a => Either a Value -> IO b-showJSON ejson =- case ejson of- Left err -> hPutStrLn stderr (show err) >> exitFailure- Right res -> putStr (encode (res :: Value)) >> exitSuccess+data Options = Options+ { optInput :: Maybe FilePath+ -- ^ 'Nothing' means @stdin@.+ , optOutput :: Maybe FilePath+ -- ^ 'Nothing' means @stdout@.+ } +-- | Name of the executable.++self :: String+self = "yaml2json"++-- | Parse options; handle parse errors, @--help@, @--version@.++options :: IO Options+options =+ execParser $+ info (helper <*> versionOption self <*> numericVersionOption <*> programOptions)+ (headerDoc hdoc)++ where+ hdoc = Just $ vcat $ map pretty+ [ versionText self+ , "Convert YAML to JSON."+ ]++ programOptions = Options <$> oInput <*> oOutput++ oInput :: Parser (Maybe FilePath)+ oInput = dashToNothing <$> do+ strArgument+ $ metavar "IN"+ <> value "-"+ <> action "file"+ <> help "The input file containing the YAML document; use '-' for stdin (default)."++ oOutput :: Parser (Maybe FilePath)+ oOutput = dashToNothing <$> do+ strOption+ $ long "output"+ <> short 'o'+ <> value "-"+ <> metavar "OUT"+ <> action "file"+ <> help "The file to hold the produced JSON document; use '-' for stdout (default)."++ main :: IO () main = do- args <- getArgs- case args of- -- strict getContents will read in all of stdin at once- (["-h"]) -> helpMessage- (["--help"]) -> helpMessage- (["-"]) -> getContents >>= showJSON . decodeEither'- ([f]) -> decodeFileEither f >>= showJSON- _ -> helpMessage+ Options{ optInput, optOutput } <- options + -- Input YAML.+ result <- case optInput of+ -- strict getContents will read in all of stdin at once+ Nothing -> decodeEither' <$> S.getContents+ Just f -> decodeFileEither f++ -- Output JSON.+ case result of+ Left err -> die $ show err+ Right val -> do+ let json = encode (val :: Value)+ maybe L.putStr L.writeFile optOutput json
src/Data/Yaml/Config.hs view
@@ -33,7 +33,13 @@ import Data.Semigroup import Data.List.NonEmpty (nonEmpty) import Data.Aeson+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.Key as K+import qualified Data.Aeson.KeyMap as H+import Data.Aeson.KeyMap (KeyMap)+#else import qualified Data.HashMap.Strict as H+#endif import Data.Text (Text, pack) import System.Environment (getArgs, getEnvironment) import Control.Arrow ((***))@@ -45,6 +51,16 @@ import Data.Maybe (fromMaybe) import qualified Data.Text as T +#if MIN_VERSION_aeson(2,0,0)+fromText :: T.Text -> Key+fromText = K.fromText+#else+fromText :: T.Text -> T.Text+fromText = id++type KeyMap a = H.HashMap T.Text a+#endif+ newtype MergedValue = MergedValue { getMergedValue :: Value } instance Semigroup MergedValue where@@ -64,7 +80,7 @@ -- -- @since 0.8.16 applyEnvValue :: Bool -- ^ require an environment variable to be present?- -> H.HashMap Text Text -> Value -> Value+ -> KeyMap Text -> Value -> Value applyEnvValue requireEnv' env = goV where@@ -74,7 +90,7 @@ t2 <- T.stripPrefix "_env:" t1 let (name, t3) = T.break (== ':') t2 mdef = fmap parseValue $ T.stripPrefix ":" t3- Just $ case H.lookup name env of+ Just $ case H.lookup (fromText name) env of Just val -> -- If the default value parses as a String, we treat the -- environment variable as a raw value and do not parse it.@@ -101,8 +117,8 @@ -- | Get the actual environment as a @HashMap@ from @Text@ to @Text@. -- -- @since 0.8.16-getCurrentEnv :: IO (H.HashMap Text Text)-getCurrentEnv = fmap (H.fromList . map (pack *** pack)) getEnvironment+getCurrentEnv :: IO (KeyMap Text)+getCurrentEnv = fmap (H.fromList . map (fromText . pack *** pack)) getEnvironment -- | A convenience wrapper around 'applyEnvValue' and 'getCurrentEnv' --@@ -118,8 +134,8 @@ data EnvUsage = IgnoreEnv | UseEnv | RequireEnv- | UseCustomEnv (H.HashMap Text Text)- | RequireCustomEnv (H.HashMap Text Text)+ | UseCustomEnv (KeyMap Text)+ | RequireCustomEnv (KeyMap Text) -- | Do not use any environment variables, instead relying on defaults values -- in the config file.@@ -146,14 +162,14 @@ -- @HashMap@ as the environment. -- -- @since 0.8.16-useCustomEnv :: H.HashMap Text Text -> EnvUsage+useCustomEnv :: KeyMap Text -> EnvUsage useCustomEnv = UseCustomEnv -- | Same as 'requireEnv', but instead of the actual environment, use the -- provided @HashMap@ as the environment. -- -- @since 0.8.16-requireCustomEnv :: H.HashMap Text Text -> EnvUsage+requireCustomEnv :: KeyMap Text -> EnvUsage requireCustomEnv = RequireCustomEnv -- | Load the settings from the following three sources:
src/Data/Yaml/Internal.hs view
@@ -9,12 +9,14 @@ , prettyPrintParseException , Warning(..) , parse+ , Parse , decodeHelper , decodeHelper_ , decodeAllHelper , decodeAllHelper_ , textToScientific , stringScalar+ , StringStyle , defaultStringStyle , isSpecialString , specialStrings@@ -32,9 +34,24 @@ import Control.Monad.Trans.Resource (ResourceT, runResourceT) import Control.Monad.State.Strict import Control.Monad.Reader+#if MIN_VERSION_aeson(2,1,2)+import Data.Aeson hiding (AesonException)+#else import Data.Aeson-import Data.Aeson.Internal (JSONPath, JSONPathElement(..), formatError)+#endif+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.Key as K+import qualified Data.Aeson.KeyMap as M+import Data.Aeson.KeyMap (KeyMap)+#else+import qualified Data.HashMap.Strict as M+#endif+#if MIN_VERSION_aeson(2,2,0)+import Data.Aeson.Types hiding (AesonException, parse)+#else import Data.Aeson.Types hiding (parse)+import Data.Aeson.Internal (JSONPath, JSONPathElement(..), formatError)+#endif import qualified Data.Attoparsec.Text as Atto import Data.Bits (shiftL, (.|.)) import Data.ByteString (ByteString)@@ -42,17 +59,16 @@ import qualified Data.ByteString.Lazy as BL import Data.ByteString.Builder.Scientific (scientificBuilder) import Data.Char (toUpper, ord)-import Data.List+import qualified Data.List as List import Data.Conduit ((.|), ConduitM, runConduit) import qualified Data.Conduit.List as CL-import qualified Data.HashMap.Strict as M import qualified Data.HashSet as HashSet import Data.Map (Map) import qualified Data.Map as Map import Data.Set (Set) import qualified Data.Set as Set import Data.Scientific (Scientific, base10Exponent, coefficient)-import Data.Text (Text, pack)+import Data.Text (Text) import qualified Data.Text as T import Data.Text.Encoding (decodeUtf8With, encodeUtf8) import Data.Text.Encoding.Error (lenientDecode)@@ -63,6 +79,23 @@ import qualified Text.Libyaml as Y import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile) +#if MIN_VERSION_aeson(2,0,0)+fromText :: T.Text -> K.Key+fromText = K.fromText++toText :: K.Key -> T.Text+toText = K.toText+#else+fromText :: T.Text -> T.Text+fromText = id++toText :: Key -> T.Text+toText = id++type KeyMap a = M.HashMap Text a+type Key = Text+#endif+ data ParseException = NonScalarKey | UnknownAlias { _anchorName :: Y.AnchorName } | UnexpectedEvent { _received :: Maybe Event@@ -255,9 +288,9 @@ o <- local (Index n :) parseO parseS (succ n) a $ front . (:) o -parseM :: Set Text+parseM :: Set Key -> Y.Anchor- -> M.HashMap Text Value+ -> KeyMap Value -> ReaderT JSONPath (ConduitM Event o Parse) Value parseM mergedKeys a front = do me <- lift CL.head@@ -268,12 +301,12 @@ return res _ -> do s <- case me of- Just (EventScalar v tag style a') -> parseScalar v a' style tag+ Just (EventScalar v tag style a') -> fromText <$> parseScalar v a' style tag Just (EventAlias an) -> do m <- lookupAnchor an case m of Nothing -> liftIO $ throwIO $ UnknownAlias an- Just (String t) -> return t+ Just (String t) -> return $ fromText t Just v -> liftIO $ throwIO $ NonStringKeyAlias an v _ -> do path <- ask@@ -286,17 +319,17 @@ path <- reverse <$> ask addWarning (DuplicateKey path) return (Set.delete s mergedKeys, M.insert s o front)- if s == pack "<<"+ if s == "<<" then case o of Object l -> return (merge l)- Array l -> return $ merge $ foldl' mergeObjects M.empty $ V.toList l+ Array l -> return $ merge $ List.foldl' mergeObjects M.empty $ V.toList l _ -> al else al parseM mergedKeys' a al' where mergeObjects al (Object om) = M.union al om mergeObjects al _ = al - merge xs = (Set.fromList (M.keys xs \\ M.keys front), M.union front xs)+ merge xs = (Set.fromList (M.keys xs List.\\ M.keys front), M.union front xs) parseSrc :: ReaderT JSONPath (ConduitM Event Void Parse) val -> ConduitM () Event Parse ()@@ -417,7 +450,7 @@ : foldr pairToEvents (EventMappingEnd : rest) (M.toList o) where pairToEvents :: Pair -> [Y.Event] -> [Y.Event]- pairToEvents (k, v) = objToEvents' (String k) . objToEvents' v+ pairToEvents (k, v) = objToEvents' (String $ toText k) . objToEvents' v objToEvents' (String s) rest = stringScalar stringStyle Nothing s : rest
src/Data/Yaml/Pretty.hs view
@@ -18,10 +18,16 @@ #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>)) #endif+import Data.Bifunctor (first)+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.Key as K+import qualified Data.Aeson.KeyMap as HM+#else+import qualified Data.HashMap.Strict as HM+#endif import Data.Aeson.Types import Data.ByteString (ByteString) import Data.Function (on)-import qualified Data.HashMap.Strict as HM import Data.List (sortBy) #if !MIN_VERSION_base(4,8,0) import Data.Monoid@@ -31,6 +37,16 @@ import Data.Yaml.Builder +#if MIN_VERSION_aeson(2,0,0)+toText :: Key -> Text+toText = K.toText+#else+toText :: Key -> Text+toText = id++type Key = Text+#endif+ -- | -- @since 0.8.13 data Config = Config@@ -72,7 +88,7 @@ select | confDropNull cfg = HM.filter (/= Null) | otherwise = id- in mapping (sort $ HM.toList $ HM.map go $ select o)+ in mapping (sort $ fmap (first toText) $ HM.toList $ HM.map go $ select o) go (Array a) = array (go <$> V.toList a) go Null = null go (String s) = string s
test/Data/Yaml/IncludeSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE OverloadedStrings #-} module Data.Yaml.IncludeSpec (main, spec) where@@ -6,7 +7,11 @@ import Data.List (isPrefixOf) import qualified Data.ByteString.Lazy as LB import Data.Aeson+#if MIN_VERSION_aeson(2,2,0)+import Data.Aeson.Types (JSONPathElement(..))+#else import Data.Aeson.Internal (JSONPathElement(..))+#endif import Data.Yaml (ParseException(InvalidYaml)) import Data.Yaml.Include import Data.Yaml.Internal
test/Data/YamlSpec.hs view
@@ -32,10 +32,18 @@ import qualified Data.Yaml.Pretty as Pretty import Data.Yaml (object, array, (.=)) import Data.Maybe+import qualified Data.HashMap.Strict as HM+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.KeyMap as M+import qualified Data.Aeson.Key as K+import Data.Aeson.KeyMap (KeyMap)+#else import qualified Data.HashMap.Strict as M+#endif import qualified Data.Text as T import Data.Aeson.TH import Data.Scientific (Scientific)+import Data.String (fromString) import Data.Text (Text) import Data.Text.Encoding (decodeUtf8, encodeUtf8) import Data.Vector (Vector)@@ -45,6 +53,23 @@ import System.IO (hClose) import System.IO.Temp (withSystemTempFile) +#if MIN_VERSION_aeson(2,0,0)+fromText :: T.Text -> K.Key+fromText = K.fromText++toText :: K.Key -> T.Text+toText = K.toText+#else+fromText :: T.Text -> T.Text+fromText = id++toText :: Key -> T.Text+toText = id++type KeyMap a = M.HashMap Text a+type Key = Text+#endif+ data TestJSON = TestJSON { string :: Text , number :: Int@@ -179,7 +204,7 @@ describe "special keys" $ do let tester key = it (T.unpack key) $- let value = object [key .= True]+ let value = object [fromText key .= True] in D.encode value `shouldDecode` value mapM_ tester specialStrings @@ -551,7 +576,7 @@ mkStrScalar = D.String . T.pack mappingKey :: D.Value-> String -> D.Value-mappingKey (D.Object m) k = (fromJust . M.lookup (T.pack k) $ m)+mappingKey (D.Object m) k = (fromJust . M.lookup (fromText $ T.pack k) $ m) mappingKey _ _ = error "expected Object" sample :: D.Value@@ -658,7 +683,9 @@ caseSimpleMappingAlias :: Assertion caseSimpleMappingAlias = "map: &anch\n key1: foo\n key2: baz\nmap2: *anch" `shouldDecode`- object [(T.pack "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (T.pack "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]+ object [(packStr "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (packStr "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]+ where+ packStr = fromText . T.pack caseMappingAliasBeforeAnchor :: Assertion caseMappingAliasBeforeAnchor =@@ -811,10 +838,10 @@ res <- D.decodeFileEither fp either (Left . show) Right res `shouldBe` Right val -caseSpecialKeys :: (HashMap Text () -> B8.ByteString) -> Assertion+caseSpecialKeys :: (KeyMap () -> B8.ByteString) -> Assertion caseSpecialKeys encoder = do let keys = T.words "true false NO YES 1.2 1e5 null"- bs = encoder $ M.fromList $ map (, ()) keys+ bs = encoder $ M.fromList $ map (, ()) $ fmap fromText keys text = decodeUtf8 bs forM_ keys $ \key -> do let quoted = T.concat ["'", key, "'"]
yaml.cabal view
@@ -1,13 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.33.0.+-- This file has been generated from package.yaml by hpack version 0.35.1. -- -- see: https://github.com/sol/hpack------ hash: 55c85c8d4d3074a558a82e30a2592ecff9db2e6f1571547c73d26ba44bfc1c20 name: yaml-version: 0.11.5.0+version: 0.11.11.2 synopsis: Support for parsing and rendering YAML documents. description: README and API documentation are available at <https://www.stackage.org/package/yaml> category: Data@@ -62,8 +60,9 @@ Paths_yaml hs-source-dirs: src- other-extensions: LambdaCase- ghc-options: -Wall+ other-extensions:+ LambdaCase+ ghc-options: -Wall -Wcompat build-depends: aeson >=0.11 , attoparsec >=0.11.3.0@@ -73,18 +72,15 @@ , containers , directory , filepath- , libyaml >=0.1 && <0.2+ , libyaml ==0.1.* , mtl- , resourcet >=0.3 && <1.3+ , resourcet >=0.3 && <1.4 , scientific >=0.3 , template-haskell , text , transformers >=0.1 , unordered-containers , vector- if !impl(ghc >= 8.0)- build-depends:- semigroups default-language: Haskell2010 executable examples@@ -95,7 +91,7 @@ Paths_yaml hs-source-dirs: examples- ghc-options: -Wall+ ghc-options: -Wall -Wcompat build-depends: aeson >=0.11 , attoparsec >=0.11.3.0@@ -105,32 +101,31 @@ , containers , directory , filepath- , libyaml >=0.1 && <0.2+ , libyaml ==0.1.* , mtl- , resourcet >=0.3 && <1.3+ , resourcet >=0.3 && <1.4 , scientific >=0.3 , template-haskell , text , transformers >=0.1 , unordered-containers , vector- if !impl(ghc >= 8.0)- build-depends:- semigroups+ default-language: Haskell2010 if flag(no-examples) buildable: False else build-depends: raw-strings-qq , yaml- default-language: Haskell2010 executable json2yaml main-is: json2yaml.hs other-modules:+ Common Paths_yaml hs-source-dirs: exe+ ghc-options: -Wall -Wcompat build-depends: aeson >=0.11 , attoparsec >=0.11.3.0@@ -140,9 +135,10 @@ , containers , directory , filepath- , libyaml >=0.1 && <0.2+ , libyaml ==0.1.* , mtl- , resourcet >=0.3 && <1.3+ , optparse-applicative+ , resourcet >=0.3 && <1.4 , scientific >=0.3 , template-haskell , text@@ -150,19 +146,22 @@ , unordered-containers , vector , yaml- if !impl(ghc >= 8.0)- build-depends:- semigroups+ default-language: Haskell2010 if flag(no-exe) buildable: False- default-language: Haskell2010 executable yaml2json main-is: yaml2json.hs other-modules:+ Common Paths_yaml hs-source-dirs: exe+ other-extensions:+ CPP+ LambdaCase+ NamedFieldPuns+ ghc-options: -Wall -Wcompat build-depends: aeson >=0.11 , attoparsec >=0.11.3.0@@ -172,9 +171,10 @@ , containers , directory , filepath- , libyaml >=0.1 && <0.2+ , libyaml ==0.1.* , mtl- , resourcet >=0.3 && <1.3+ , optparse-applicative+ , resourcet >=0.3 && <1.4 , scientific >=0.3 , template-haskell , text@@ -182,12 +182,9 @@ , unordered-containers , vector , yaml- if !impl(ghc >= 8.0)- build-depends:- semigroups+ default-language: Haskell2010 if flag(no-exe) buildable: False- default-language: Haskell2010 test-suite spec type: exitcode-stdio-1.0@@ -199,7 +196,7 @@ Paths_yaml hs-source-dirs: test- ghc-options: -Wall "-with-rtsopts=-K1K"+ ghc-options: -Wall -Wcompat -with-rtsopts=-K1K cpp-options: -DTEST build-depends: HUnit@@ -213,11 +210,11 @@ , directory , filepath , hspec >=1.3- , libyaml >=0.1 && <0.2+ , libyaml ==0.1.* , mockery , mtl , raw-strings-qq- , resourcet >=0.3 && <1.3+ , resourcet >=0.3 && <1.4 , scientific >=0.3 , template-haskell , temporary@@ -226,7 +223,4 @@ , unordered-containers , vector , yaml- if !impl(ghc >= 8.0)- build-depends:- semigroups default-language: Haskell2010