aeson 2.2.5.0 → 2.3.0.0
raw patch · 17 files changed
+54/−41 lines, 17 filesdep ~nothunksdep ~text-iso8601new-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: nothunks, text-iso8601
API changes (from Hackage documentation)
Files
- aeson.cabal +3/−3
- changelog.md +15/−4
- src/Data/Aeson/Decoding.hs +1/−1
- src/Data/Aeson/Decoding/ByteString.hs +1/−1
- src/Data/Aeson/Decoding/ByteString/Lazy.hs +1/−1
- src/Data/Aeson/Decoding/Conversion.hs +1/−1
- src/Data/Aeson/Decoding/Text.hs +1/−1
- src/Data/Aeson/Internal/Unescape.hs +1/−1
- src/Data/Aeson/Internal/UnescapeFromText.hs +1/−1
- src/Data/Aeson/TH.hs +2/−2
- src/Data/Aeson/Types/FromJSON.hs +5/−10
- tests/DoubleToScientific.hs +1/−1
- tests/JSONTestSuite/results/n_array_spaces_vertical_tab_formfeed.tok +1/−1
- tests/JSONTestSuite/results/n_string_unescaped_ctrl_char.tok +1/−1
- tests/JSONTestSuite/results/n_string_unescaped_newline.tok +1/−1
- tests/JSONTestSuite/results/n_string_unescaped_tab.tok +1/−1
- tests/UnitTests.hs +17/−10
aeson.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: aeson-version: 2.2.5.0+version: 2.3.0.0 license: BSD-3-Clause license-file: LICENSE category: Text, Web, JSON@@ -130,7 +130,7 @@ , semialign ^>=1.3 || ^>=1.4 , strict ^>=0.5 , tagged ^>=0.8.7- , text-iso8601 ^>=0.1.1+ , text-iso8601 >=0.1.1 && < 0.3 , text-short ^>=0.1.5 , th-abstraction ^>=0.5.0.0 || ^>=0.6.0.0 || ^>=0.7.0.0 , these ^>=1.2@@ -238,7 +238,7 @@ build-depends: integer-gmp if impl(ghc >=9.2 && <9.7)- build-depends: nothunks >=0.1.4 && <0.3+ build-depends: nothunks >=0.1.4 && <0.4 source-repository head type: git
changelog.md view
@@ -1,5 +1,16 @@ For the latest version of this document, please see [https://github.com/haskell/aeson/blob/master/changelog.md](https://github.com/haskell/aeson/blob/master/changelog.md). +### 2.3.0.0 - 2026-05-21++* Fix parsing of fractional numbers to reject exponents smaller than -1024.+ This breaking change affects `FromJSON` instances of `Fixed`, `DiffTime`, and `NominalDiffTime`,+ rejecting more inputs. Error messages for `Ratio` and integral types are also slightly different+ due to reusing the same bounding logic.+* Fix typo in error message: "~~Unespected~~ Unexpected control character while parsing string literal".+* Accept 24:00:00 time of day.+* Support nothunks 0.3.+* Unset executable permissions in some test files and remove a broken symlink.+ ### 2.2.5.0 * Support `semialign-1.4`@@ -34,7 +45,7 @@ One gotcha is that internal `Text` values (in `Key`s or `Value` `String`s) will most likely retain the original input `Text` value (its underlying `Array`). It shouldn't be an issue if the `Value` is then decoded to something else so these- `Text` values disapper, but if not (e.g. `Object` keys survive)+ `Text` values disappear, but if not (e.g. `Object` keys survive) then users might want to use `Data.Text.copy`. ### 2.2.0.0@@ -54,7 +65,7 @@ In addition to `Maybe` (and `Option`) fields the `Data.Monoid.First` and `Data.Monoid.Last` are also omitted, as well as the most newtype wrappers, when their wrap omittable type (e.g. newtypes in `Data.Monoid` and `Data.Semigroup`, `Identity`, `Const`, `Tagged`, `Compose`).- Additionall "boring" types like `()` and `Proxy` are omitted as well.+ Additionally "boring" types like `()` and `Proxy` are omitted as well. As the omitting is now uniform, type arguments are also omitted (also in `Generic1` derived instance). Resolves issues:@@ -72,7 +83,7 @@ * Move `Data.Aeson.Parser` module into separate [`attoparsec-aeson`](https://hackage.haskell.org/package/attoparsec-aeson) package, as these parsers are not used by `aeson` itself anymore. * Use [`text-iso8601`](https://hackage.haskell.org/package/text-iso8601) package for parsing `time` types. These are slightly faster than previously used (copy of) `attoparsec-iso8601`. Formats accepted is slightly changed:- - The space between time and timezone offset (in `UTCTime` and `ZonedTime`) is disallowed. ISO8601 explictly forbidds it.+ - The space between time and timezone offset (in `UTCTime` and `ZonedTime`) is disallowed. ISO8601 explicitly forbids it. - The timezone offsets can be in range -23:59..23:59. This is how Python, joda-time etc seems to do. (Previously the range was -12..+14) * Remove internal `Data.Aeson.Internal` and `Data.Aeson.Internal.Time` modules. Everything from the former is exported elsewhere (`Data.Aeson.Types`), the latter was truly internal.@@ -235,7 +246,7 @@ parseJSON = gParseJSON defaultOptions { rejectUnknownFields = True } ``` -* `FromJSON` instance of `Ratio a` now parses numbers in addtion to+* `FromJSON` instance of `Ratio a` now parses numbers in addition to standard `{numerator=..., denumerator=...}` encoding. Thanks to Aleksey Khudyakov.
src/Data/Aeson/Decoding.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-}--- | Convertion to and from @aeson@ 'A.Value'.+-- | Conversion to and from @aeson@ 'A.Value'. -- module Data.Aeson.Decoding ( decode,
src/Data/Aeson/Decoding/ByteString.hs view
@@ -163,7 +163,7 @@ Just (_, bs') -> goEsc (n + 1) bs' errEnd = err "Unexpected end-of-input while parsing string literal"- errCC = err "Unespected control character while parsing string literal"+ errCC = err "Unexpected control character while parsing string literal" ------------------------------------------------------------------------------- -- Number
src/Data/Aeson/Decoding/ByteString/Lazy.hs view
@@ -169,7 +169,7 @@ Just (_, bs') -> goEsc (n + 1) bs' errEnd = err "Unexpected end-of-input while parsing string literal"- errCC = err "Unespected control character while parsing string literal"+ errCC = err "Unexpected control character while parsing string literal" ------------------------------------------------------------------------------- -- Number
src/Data/Aeson/Decoding/Conversion.hs view
@@ -87,7 +87,7 @@ -> (e -> r) -> ([(Key, A.Value)] -> k -> r) -> r- -- here we don't stricly need bang on !v as KM is a Strict (in values) map.+ -- here we don't strictly need bang on !v as KM is a Strict (in values) map. -- but we force the value sooner. goR !acc (TkPair t toks) g f = convert toks g $ \ !v k -> goR ((t , v) : acc) k g f goR !acc (TkRecordEnd k) _ f = f acc k
src/Data/Aeson/Decoding/Text.hs view
@@ -173,7 +173,7 @@ Just (_, bs') -> goEsc (n + 1) bs' errEnd = err "Unexpected end-of-input while parsing string literal"- errCC = err "Unespected control character while parsing string literal"+ errCC = err "Unexpected control character while parsing string literal" ------------------------------------------------------------------------------- -- Number
src/Data/Aeson/Internal/Unescape.hs view
@@ -29,7 +29,7 @@ -- | Unescape JSON text literal. ----- This function is exporeted mostly for testing and benchmarking purposes.+-- This function is exported mostly for testing and benchmarking purposes. unescapeText :: ByteString -> Either UnicodeException Text unescapeText = unsafeDupablePerformIO . try . unescapeTextIO
src/Data/Aeson/Internal/UnescapeFromText.hs view
@@ -24,7 +24,7 @@ -- | Unescape JSON text literal. ----- This function is exporeted mostly for testing and benchmarking purposes.+-- This function is exported mostly for testing and benchmarking purposes. unescapeFromText :: Text -> Either UnicodeException Text unescapeFromText = unsafeDupablePerformIO . try . unescapeFromTextIO
src/Data/Aeson/TH.hs view
@@ -955,7 +955,7 @@ | (field, argTy) <- zip fields argTys ] --- A hack, as I'm too lazy to changge code to not assume fields are non empty.+-- A hack, as I'm too lazy to change code to not assume fields are non empty. nonEmpty :: [a] -> (a, [a]) nonEmpty (x:xs) = (x,xs) nonEmpty [] = error "unexpected empty list"@@ -1276,7 +1276,7 @@ varE $ case M.lookup tyName tvMap of Just (tfjoExp, tfjExp, tfjlExp) -> case list of Omit -> tfjoExp- Single -> tfjExp + Single -> tfjExp Plural -> tfjlExp Nothing -> jsonFunValOrListName list jf Arity0 dispatchFunByType jc jf conName tvMap list (SigT ty _) =
src/Data/Aeson/Types/FromJSON.hs view
@@ -796,11 +796,13 @@ withBoundedScientific_ :: (Parser a -> Parser a) -> (Scientific -> Parser a) -> Value -> Parser a withBoundedScientific_ whenFail f (Number scientific) = if exp10 > 1024- then whenFail (fail msg)+ then whenFail (fail (msg "greater than 1024"))+ else if exp10 < -1024+ then whenFail (fail (msg "less than -1024")) else f scientific where exp10 = base10Exponent scientific- msg = "found a number with exponent " ++ show exp10 ++ ", but it must not be greater than 1024"+ msg req = "found a number with exponent " ++ show exp10 ++ ", but it must not be " ++ req withBoundedScientific_ whenFail _ v = whenFail (typeMismatch "Number" v) @@ -1706,14 +1708,7 @@ _ -> Scientific.toRealFloat <$> parseScientificText t instance (FromJSON a, Integral a) => FromJSON (Ratio a) where- parseJSON (Number x)- | exp10 <= 1024- , exp10 >= -1024 = return $! realToFrac x- | otherwise = prependContext "Ratio" $ fail msg- where- exp10 = base10Exponent x- msg = "found a number with exponent " ++ show exp10- ++ ", but it must not be greater than 1024 or less than -1024"+ parseJSON n@(Number _) = withBoundedScientific "Ratio" (($!) pure . realToFrac) n parseJSON o = objParser o where objParser = withObject "Rational" $ \obj -> do
tests/DoubleToScientific.hs view
@@ -114,7 +114,7 @@ (s, e, lower_boundary_is_closer) = decodeFloat' v lowerBoundaryCloser' = if lower_boundary_is_closer then lowerBoundaryCloser else id --- | return significant, exponent and whether lower boundery is closer.+-- | return significand, exponent and whether lower boundary is closer. -- -- GHC's decodeFloat does "weird" stuff to denormal doubles, -- that messes up our delta calculation.
tests/JSONTestSuite/results/n_array_spaces_vertical_tab_formfeed.tok view
@@ -1,3 +1,3 @@ TkArrayOpen TkItem-TkErr "Unespected control character while parsing string literal"+TkErr "Unexpected control character while parsing string literal"
tests/JSONTestSuite/results/n_string_unescaped_ctrl_char.tok view
@@ -1,3 +1,3 @@ TkArrayOpen TkItem-TkErr "Unespected control character while parsing string literal"+TkErr "Unexpected control character while parsing string literal"
tests/JSONTestSuite/results/n_string_unescaped_newline.tok view
@@ -1,3 +1,3 @@ TkArrayOpen TkItem-TkErr "Unespected control character while parsing string literal"+TkErr "Unexpected control character while parsing string literal"
tests/JSONTestSuite/results/n_string_unescaped_tab.tok view
@@ -1,3 +1,3 @@ TkArrayOpen TkItem-TkErr "Unespected control character while parsing string literal"+TkErr "Unexpected control character while parsing string literal"
tests/UnitTests.hs view
@@ -38,6 +38,7 @@ , Value(..), camelTo, camelTo2 , defaultOptions, formatPath, formatRelativePath, omitNothingFields, parse) import Data.Char (toUpper, GeneralCategory(Control,Surrogate), generalCategory)+import Data.Fixed (Nano) import Data.HashMap.Strict (HashMap) import Data.Kind (Type) import Data.List (isSuffixOf)@@ -87,7 +88,8 @@ _ -> s -- shouldn't happen? where split c' s' = map L.unpack $ L.split c' $ L.pack s'- capitalize t = toUpper (head t) : tail t+ capitalize [] = []+ capitalize (x:xs) = toUpper x : xs data Wibble = Wibble {@@ -458,17 +460,22 @@ (eitherDecode "1.37" :: Either String Rational) bigRationalDecoding :: Assertion-bigRationalDecoding =- assertEqual "Decoding an Integer with a large exponent should fail"- (Left "Error in $: parsing Ratio failed, found a number with exponent 2000, but it must not be greater than 1024 or less than -1024")+bigRationalDecoding = do+ assertEqual "Decoding a Rational with a large exponent should fail"+ (Left "Error in $: parsing Ratio failed, found a number with exponent 2000, but it must not be greater than 1024") ((eitherDecode :: L.ByteString -> Either String Rational) "1e2000")--smallRationalDecoding :: Assertion-smallRationalDecoding =- assertEqual "Decoding an Integer with a large exponent should fail"- (Left "Error in $: parsing Ratio failed, found a number with exponent -2000, but it must not be greater than 1024 or less than -1024")+ assertEqual "Decoding a Rational with a small exponent should fail"+ (Left "Error in $: parsing Ratio failed, found a number with exponent -2000, but it must not be less than -1024") ((eitherDecode :: L.ByteString -> Either String Rational) "1e-2000") +bigFixedDecoding :: Assertion+bigFixedDecoding = do+ assertEqual "Decoding a Fixed with a large exponent should fail"+ (Left "Error in $: parsing Fixed failed, found a number with exponent 9999, but it must not be greater than 1024")+ ((eitherDecode :: L.ByteString -> Either String Nano) "1e9999")+ assertEqual "Decoding a Fixed with a small exponent should fail"+ (Left "Error in $: parsing Fixed failed, found a number with exponent -9999, but it must not be less than -1024")+ ((eitherDecode :: L.ByteString -> Either String Nano) "1e-9999") bigScientificExponent :: Assertion bigScientificExponent =@@ -555,7 +562,7 @@ , testCase "Ratio with denominator 0" ratioDenominator0 , testCase "Rational parses number" rationalNumber , testCase "Big rational" bigRationalDecoding- , testCase "Small rational" smallRationalDecoding+ , testCase "Big fixed" bigFixedDecoding , testCase "Big scientific exponent" bigScientificExponent , testCase "Big integer decoding" bigIntegerDecoding , testCase "Big natural decoding" bigNaturalDecoding