@@ -55,6 +55,7 @@ module Data.Aeson.Types.FromJSON
5555 , withNumber
5656 , withScientific
5757 , withBool
58+ , withEmbeddedJSON
5859
5960 -- * Functions
6061 , fromJSON
@@ -82,6 +83,7 @@ import Prelude.Compat
8283import Control.Applicative ((<|>), Const(..))
8384import Control.Monad ((<=<), zipWithM)
8485import Data.Aeson.Internal.Functions (mapKey)
86+import Data.Aeson.Parser.Internal (eitherDecodeWith, jsonEOF)
8587import Data.Aeson.Types.Generic
8688import Data.Aeson.Types.Internal
8789import Data.Attoparsec.Number (Number(..))
@@ -114,6 +116,7 @@ import GHC.Generics
114116import Numeric.Natural (Natural)
115117import Text.ParserCombinators.ReadP (readP_to_S)
116118import Unsafe.Coerce (unsafeCoerce)
119+import qualified Data.Aeson.Compat as Compat
117120import qualified Data.Aeson.Parser.Time as Time
118121import qualified Data.Attoparsec.ByteString.Char8 as A (endOfInput, parseOnly, scientific)
119122import qualified Data.DList as DList
@@ -665,6 +668,16 @@ withBool _ f (Bool arr) = f arr
665668withBool expected _ v = typeMismatch expected v
666669{-# INLINE withBool #-}
667670
671+-- | Decode a nested JSON-encoded string.
672+withEmbeddedJSON :: (FromJSON a) => String -> (Value -> Parser a) -> Value -> Parser a
673+withEmbeddedJSON _ innerParser (String txt) =
674+ either fail innerParser $ eitherDecode (Compat.fromStrict $ T.encodeUtf8 txt)
675+ where
676+ eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON
677+ eitherFormatError = either (Left . uncurry formatError) Right
678+withEmbeddedJSON name _ v = typeMismatch name v
679+{-# INLINE withEmbeddedJSON #-}
680+
668681-- | Convert a value from JSON, failing if the types do not match.
669682fromJSON :: (FromJSON a) => Value -> Result a
670683fromJSON = parse parseJSON