aeson-diff 1.1.0.12 → 1.1.0.13
raw patch · 5 files changed
+85/−23 lines, 5 filesdep +yamldep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: yaml
Dependency ranges changed: base
API changes (from Hackage documentation)
Files
- aeson-diff.cabal +5/−1
- src/Codec.hs +37/−0
- src/diff.hs +23/−11
- src/patch.hs +19/−10
- stack.yaml +1/−1
aeson-diff.cabal view
@@ -1,5 +1,5 @@ name: aeson-diff-version: 1.1.0.12+version: 1.1.0.13 synopsis: Extract and apply patches to JSON documents. description: .@@ -46,21 +46,25 @@ default-language: Haskell2010 hs-source-dirs: src main-is: diff.hs+ other-modules: Codec build-depends: base , aeson >= 2.0.3 , aeson-diff , bytestring , optparse-applicative+ , yaml executable json-patch default-language: Haskell2010 hs-source-dirs: src main-is: patch.hs+ other-modules: Codec build-depends: base , aeson >= 2.0.3 , aeson-diff , bytestring , optparse-applicative+ , yaml test-suite properties default-language: Haskell2010
+ src/Codec.hs view
@@ -0,0 +1,37 @@+module Codec (encode, decode, ForceFormat (..)) where++import qualified Data.Aeson as Aeson+import qualified Data.Yaml as Yaml+import qualified Data.ByteString.Lazy as BL+import Control.Applicative ((<|>))+import Data.Char (toLower)+import Data.List (isSuffixOf)++data ForceFormat = ForceYaml | AutodetectFormat deriving (Show, Eq)++isYamlPath :: [Char] -> Bool+isYamlPath fn =+ ".yaml" `isSuffixOf` map toLower fn+ || ".yml" `isSuffixOf` map toLower fn++isJsonPath :: [Char] -> Bool+isJsonPath fn =+ ".json" `isSuffixOf` map toLower fn++decode :: Aeson.FromJSON a => ForceFormat -> Maybe FilePath -> BL.ByteString -> Maybe a+decode ForceYaml _ = decodeYamlFirst+decode AutodetectFormat (Just fn) | isYamlPath fn = decodeYamlFirst+decode AutodetectFormat (Just fn) | isJsonPath fn = Aeson.decode+decode AutodetectFormat _ = decodeJsonFirst+++decodeYamlFirst :: Aeson.FromJSON a => BL.ByteString -> Maybe a+decodeYamlFirst s = Yaml.decodeThrow (BL.toStrict s) <|> Aeson.decode s++decodeJsonFirst :: Aeson.FromJSON a => BL.ByteString -> Maybe a+decodeJsonFirst s = Aeson.decode s <|> Yaml.decodeThrow (BL.toStrict s)++encode :: Aeson.ToJSON a => ForceFormat -> Maybe FilePath -> a -> BL.ByteString+encode ForceYaml _ = BL.fromStrict . Yaml.encode+encode AutodetectFormat (Just fn) | isYamlPath fn = BL.fromStrict . Yaml.encode+encode AutodetectFormat _ = Aeson.encode
src/diff.hs view
@@ -3,7 +3,8 @@ module Main (main) where import Control.Exception (bracket)-import Data.Aeson (Value, encode, decode)+import Codec (encode, decode, ForceFormat(..))+import Data.Aeson (Value) import Data.Aeson.Diff (Config(Config), diff') import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy as BSL@@ -19,10 +20,12 @@ , optionOut :: File , optionFrom :: File , optionTo :: File+ , optionYaml :: Bool } data Configuration = Configuration- { cfgTst :: Bool+ { cfgOptions :: DiffOptions+ , cfgTst :: Bool , cfgOut :: Handle , cfgFrom :: Handle , cfgTo :: Handle@@ -48,6 +51,10 @@ <*> argument fileP ( metavar "TO" )+ <*> switch+ ( long "yaml"+ <> help "Use yaml decoding and encoding."+ ) where fileP = do s <- readerAsk@@ -55,11 +62,14 @@ "-" -> Nothing _ -> Just s -jsonFile :: Handle -> IO Value-jsonFile fp = do+jsonFile :: Handle -> ForceFormat -> File -> IO Value+jsonFile fp mformat mfilepath = do s <- BS.hGetContents fp- case decode (BSL.fromStrict s) of- Nothing -> error "Could not parse as JSON"+ case decode mformat mfilepath (BSL.fromStrict s) of+ Nothing ->+ case mformat of+ ForceYaml -> error "Could not parse as YAML"+ AutodetectFormat -> error "Could not parse file. Make sure the file contents and the extension correspond: i.e. use '.json' for JSON files." Just v -> return v run :: DiffOptions -> IO ()@@ -74,9 +84,10 @@ openw (Just p) = openFile p WriteMode load :: DiffOptions -> IO Configuration- load DiffOptions{..} =+ load options@DiffOptions{..} = Configuration- <$> pure optionTst+ <$> pure options+ <*> pure optionTst <*> openw optionOut <*> openr optionFrom <*> openr optionTo@@ -89,11 +100,12 @@ process :: Configuration -> IO () process Configuration{..} = do- json_from <- jsonFile cfgFrom- json_to <- jsonFile cfgTo+ let mformat = if optionYaml cfgOptions then ForceYaml else AutodetectFormat+ json_from <- jsonFile cfgFrom mformat (optionFrom cfgOptions)+ json_to <- jsonFile cfgTo mformat (optionTo cfgOptions) let c = Config cfgTst let p = diff' c json_from json_to- BS.hPutStrLn cfgOut $ BSL.toStrict (encode p)+ BS.hPutStrLn cfgOut $ BSL.toStrict (encode mformat (optionOut cfgOptions) p) main :: IO () main = execParser opts >>= run
src/patch.hs view
@@ -3,11 +3,12 @@ module Main (main) where import Control.Exception (bracket)-import Data.Aeson (Result(Error, Success), Value, decode, encode, fromJSON)+import Codec (decode, encode, ForceFormat(..))+import Data.Aeson (Result(Error, Success), Value, fromJSON) import Data.Aeson.Diff (patch) import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy as BSL-import Options.Applicative (fullDesc, info, execParser, helper, metavar, progDesc, argument, help, value, long, option, short)+import Options.Applicative (fullDesc, info, execParser, helper, metavar, progDesc, argument, help, value, long, option, short, switch) import Options.Applicative.Types (Parser, readerAsk) import System.IO (Handle, IOMode(ReadMode, WriteMode), hClose, openFile, stdin, stdout) @@ -18,10 +19,12 @@ { optionOut :: File -- ^ JSON destination , optionPatch :: File -- ^ Patch input , optionFrom :: File -- ^ JSON source+ , optionYaml :: Bool } data Configuration = Configuration- { cfgOut :: Handle+ { cfgOptions :: PatchOptions+ , cfgOut :: Handle , cfgPatch :: Handle , cfgFrom :: Handle }@@ -43,6 +46,10 @@ ( metavar "FROM" <> help "JSON file to patch." )+ <*> switch+ ( long "yaml"+ <> help "Use yaml decoding and encoding."+ ) where fileP = do s <- readerAsk@@ -50,10 +57,10 @@ "-" -> Nothing _ -> Just s -jsonRead :: Handle -> IO Value-jsonRead fp = do+jsonRead :: Handle -> ForceFormat -> File -> IO Value+jsonRead fp mformat mfilename = do s <- BS.hGetContents fp- case decode (BSL.fromStrict s) of+ case decode mformat mfilename (BSL.fromStrict s) of Nothing -> error "Could not parse as JSON" Just v -> return v @@ -71,7 +78,8 @@ load :: PatchOptions -> IO Configuration load PatchOptions{..} = Configuration- <$> openw optionOut+ <$> pure opt+ <*> openw optionOut <*> openr optionPatch <*> openr optionFrom @@ -83,11 +91,12 @@ process :: Configuration -> IO () process Configuration{..} = do- json_patch <- jsonRead cfgPatch- json_from <- jsonRead cfgFrom+ let mformat = if optionYaml cfgOptions then ForceYaml else AutodetectFormat+ json_patch <- jsonRead cfgPatch mformat (optionPatch cfgOptions)+ json_from <- jsonRead cfgFrom mformat (optionFrom cfgOptions) case fromJSON json_patch >>= flip patch json_from of Error e -> error e- Success d -> BS.hPutStrLn cfgOut $ BSL.toStrict (encode d)+ Success d -> BS.hPutStrLn cfgOut $ BSL.toStrict (encode mformat (optionOut cfgOptions) d) main :: IO () main = execParser opts >>= run
stack.yaml view
@@ -1,4 +1,4 @@-resolver: lts-14.7+resolver: lts-19.1 extra-deps: [] flags: {} extra-package-dbs: []