on master help sign in
Add verboseDecode variants with accumulative errors
commit006e19b78e7facdd455db70b74e365c74389eadd authorlyxia <lysxia@gmail.com> dateWed 27 Sep 2017, 19:00 (9 years ago) parent186ff70
4 files changed+66−2
Data/Aeson.hs+40−2 Data/Aeson/Internal.hs+1 Data/Aeson/Parser/Internal.hs+20 Data/Aeson/Types/Internal.hs+5
Data/Aeson.hs+40−2
@@ -37,12 +37,16 @@ module Data.Aeson
3737 , decode'
3838 , eitherDecode
3939 , eitherDecode'
40+ , verboseDecode
41+ , verboseDecode'
4042 , encode
4143 -- ** Variants for strict bytestrings
4244 , decodeStrict
4345 , decodeStrict'
4446 , eitherDecodeStrict
4547 , eitherDecodeStrict'
48+ , verboseDecodeStrict
49+ , verboseDecodeStrict'
4650 -- * Core JSON types
4751 , Value(..)
4852 , Encoding
@@ -131,9 +135,14 @@ import Prelude.Compat
131135
132136import Data.Aeson.Types.FromJSON (ifromJSON)
133137import Data.Aeson.Encoding (encodingToLazyByteString)
134−import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json')
138+import Data.Aeson.Parser.Internal
139+ ( decodeWith, decodeStrictWith
140+ , eitherDecodeWith, eitherDecodeStrictWith
141+ , verboseDecodeWith, verboseDecodeStrictWith
142+ , jsonEOF, json, jsonEOF', json')
135143import Data.Aeson.Types
136−import Data.Aeson.Types.Internal (JSONPath, formatError)
144+import Data.Aeson.Types.Internal (JSONPath, formatError, formatErrors)
145+import Data.List.NonEmpty (NonEmpty)
137146import qualified Data.ByteString as B
138147import qualified Data.ByteString.Lazy as L
139148
@@ -221,6 +230,35 @@ eitherDecodeStrict' =
221230 eitherFormatError . eitherDecodeStrictWith jsonEOF' ifromJSON
222231{-# INLINE eitherDecodeStrict' #-}
223232
233+eitherFormatErrors
234+ :: Either (NonEmpty (JSONPath, String)) a -> Either (NonEmpty String) a
235+eitherFormatErrors = either (Left . formatErrors) Right
236+{-# INLINE eitherFormatErrors #-}
237+
238+-- | Like 'decode' but returns one or more error messages when decoding fails.
239+verboseDecode :: (FromJSON a) => L.ByteString -> Either (NonEmpty String) a
240+verboseDecode = eitherFormatErrors . verboseDecodeWith jsonEOF ifromJSON
241+{-# INLINE verboseDecode #-}
242+
243+-- | Like 'decodeStrict' but returns one or more error messages when decoding
244+-- fails.
245+verboseDecodeStrict :: (FromJSON a) => B.ByteString -> Either (NonEmpty String) a
246+verboseDecodeStrict =
247+ eitherFormatErrors . verboseDecodeStrictWith jsonEOF ifromJSON
248+{-# INLINE verboseDecodeStrict #-}
249+
250+-- | Like 'decode'' but returns one or more error messages when decoding fails.
251+verboseDecode' :: (FromJSON a) => L.ByteString -> Either (NonEmpty String) a
252+verboseDecode' = eitherFormatErrors . verboseDecodeWith jsonEOF' ifromJSON
253+{-# INLINE verboseDecode' #-}
254+
255+-- | Like 'decodeStrict'' but returns one or more error messages when decoding
256+-- fails.
257+verboseDecodeStrict' :: (FromJSON a) => B.ByteString -> Either (NonEmpty String) a
258+verboseDecodeStrict' =
259+ eitherFormatErrors . verboseDecodeStrictWith jsonEOF' ifromJSON
260+{-# INLINE verboseDecodeStrict' #-}
261+
224262-- $use
225263--
226264-- This section contains basic information on the different ways to
Data/Aeson/Internal.hs+1
@@ -18,6 +18,7 @@ module Data.Aeson.Internal
1818 , JSONPath
1919 , (<?>)
2020 , formatError
21+ , formatErrors
2122 , ifromJSON
2223 , iparse
2324 ) where
Data/Aeson/Parser/Internal.hs+20
@@ -33,6 +33,8 @@ module Data.Aeson.Parser.Internal
3333 , decodeStrictWith
3434 , eitherDecodeWith
3535 , eitherDecodeStrictWith
36+ , verboseDecodeWith
37+ , verboseDecodeStrictWith
3638 ) where
3739
3840import Prelude ()
@@ -288,6 +290,24 @@ eitherDecodeStrictWith p to s =
288290 IError (e :| _) -> Left e
289291{-# INLINE eitherDecodeStrictWith #-}
290292
293+verboseDecodeWith :: Parser Value -> (Value -> IResult a) -> L.ByteString
294+ -> Either (NonEmpty (JSONPath, String)) a
295+verboseDecodeWith p to s =
296+ case L.parse p s of
297+ L.Done _ v -> case to v of
298+ ISuccess a -> Right a
299+ IError e -> Left e
300+ L.Fail _ _ msg -> Left (([], msg) :| [])
301+{-# INLINE verboseDecodeWith #-}
302+
303+verboseDecodeStrictWith :: Parser Value -> (Value -> IResult a) -> B.ByteString
304+ -> Either (NonEmpty (JSONPath, String)) a
305+verboseDecodeStrictWith p to s =
306+ case either (\e -> IError (([], e) :| [])) to (A.parseOnly p s) of
307+ ISuccess a -> Right a
308+ IError e -> Left e
309+{-# INLINE verboseDecodeStrictWith #-}
310+
291311-- $lazy
292312--
293313-- The 'json' and 'value' parsers decouple identification from
Data/Aeson/Types/Internal.hs+5
@@ -49,6 +49,7 @@ module Data.Aeson.Types.Internal
4949 , parserCatchError
5050 , parserCatchErrors
5151 , formatError
52+ , formatErrors
5253 , (<?>)
5354 -- * Constructors and accessors
5455 , object
@@ -484,6 +485,10 @@ formatError path msg = "Error in " ++ format "$" path ++ ": " ++ msg
484485 escapeChar '\\' = "\\\\"
485486 escapeChar c = [c]
486487
488+-- | Annotate a list of error messages.
489+formatErrors :: Functor f => f (JSONPath, String) -> f String
490+formatErrors = fmap (uncurry formatError)
491+
487492-- | A key\/value pair for an 'Object'.
488493type Pair = (Text, Value)
489494