on master help sign in
merge from origin/master
d3057e4grdvnl
.hlint.yaml+6−1
@@ -3,4 +3,9 @@
3 name: "Reduce duplication"
3 name: "Reduce duplication"
4 within:
4 within:
5 - Data.Aeson.Types.ToJSON
5 - Data.Aeson.Types.ToJSON
6+- ignore:
6−- ignore: {name: "Eta reduce" }
7+ name: "Eta reduce"
8+- ignore:
9+ name: "Use newtype instead of data"
10+ within:
11+ - Data.Aeson.Types.Internal
.travis.yml+24−16
@@ -12,29 +12,37 @@ cache:
12 - $HOME/.stack
12 - $HOME/.stack
13 - $HOME/.cabsnap
13 - $HOME/.cabsnap
14 - $HOME/.cabal/packages
14 - $HOME/.cabal/packages
15+ - $HOME/.cabal/store
15
16
16before_cache:
17before_cache:
17 - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
18 - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
18− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
19+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
20+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
21+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
22+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
23+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
19
24
20matrix:
25matrix:
21 include:
26 include:
22− - env: BUILD=hlint CABALVER=2.2 GHCVER=8.4.3
27+ - env: BUILD=hlint CABALVER=2.2 GHCVER=8.4.4
23− compiler: ": #GHC 8.4.3"
28+ compiler: ": #GHC 8.4.4"
24− addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}
29+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4], sources: [hvr-ghc]}}
25− - env: BUILD=stack CABALVER=2.2 GHCVER=8.4.3 STACK_YAML=stack-bench.yaml
30+ - env: BUILD=stack CABALVER=2.2 GHCVER=8.4.4 STACK_YAML=stack-bench.yaml
26− compiler: ": #GHC 8.4.3"
31+ compiler: ": #GHC 8.4.4"
27− addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}
32+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4], sources: [hvr-ghc]}}
28− - env: BUILD=stack CABALVER=2.2 GHCVER=8.4.3 STACK_YAML=stack-ffi-unescape.yaml
33+ - env: BUILD=stack CABALVER=2.2 GHCVER=8.4.4 STACK_YAML=stack-ffi-unescape.yaml
29− compiler: ": #GHC 8.4.3"
34+ compiler: ": #GHC 8.4.4"
30− addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}
35+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4], sources: [hvr-ghc]}}
31
36
37+ - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.8.1
38+ compiler: ": #GHC 8.8.1"
39+ addons: {apt: {packages: [cabal-install-3.0,ghc-8.8.1], sources: [hvr-ghc]}}
32− - env: BUILD=cabal CABALVER=2.4 GHCVER=8.6.1
40+ - env: BUILD=cabal CABALVER=2.4 GHCVER=8.6.5
33− compiler: ": #GHC 8.6.1"
41+ compiler: ": #GHC 8.6.5"
34− addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.1], sources: [hvr-ghc]}}
42+ addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.5], sources: [hvr-ghc]}}
35− - env: BUILD=cabal CABALVER=2.2 GHCVER=8.4.3
43+ - env: BUILD=cabal CABALVER=2.2 GHCVER=8.4.4
36− compiler: ": #GHC 8.4.3"
44+ compiler: ": #GHC 8.4.4"
37− addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}
45+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4], sources: [hvr-ghc]}}
38 - env: BUILD=cabal CABALVER=2.0 GHCVER=8.2.2
46 - env: BUILD=cabal CABALVER=2.0 GHCVER=8.2.2
39 compiler: ": #GHC 8.2.2"
47 compiler: ": #GHC 8.2.2"
40 addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2], sources: [hvr-ghc]}}
48 addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2], sources: [hvr-ghc]}}
Data/Aeson.hs+9
@@ -70,6 +70,11 @@ module Data.Aeson
70 , ToJSONKeyFunction(..)
70 , ToJSONKeyFunction(..)
71 , FromJSONKey(..)
71 , FromJSONKey(..)
72 , FromJSONKeyFunction(..)
72 , FromJSONKeyFunction(..)
73+ -- *** Generic keys
74+ , GToJSONKey()
75+ , genericToJSONKey
76+ , GFromJSONKey()
77+ , genericFromJSONKey
73 -- ** Liftings to unary and binary type constructors
78 -- ** Liftings to unary and binary type constructors
74 , FromJSON1(..)
79 , FromJSON1(..)
75 , parseJSON1
80 , parseJSON1
@@ -111,6 +116,10 @@ module Data.Aeson
111 , SumEncoding(..)
116 , SumEncoding(..)
112 , camelTo2
117 , camelTo2
113 , defaultTaggedObject
118 , defaultTaggedObject
119+ -- ** Options for object keys
120+ , JSONKeyOptions
121+ , keyModifier
122+ , defaultJSONKeyOptions
114
123
115 -- * Inspecting @'Value's@
124 -- * Inspecting @'Value's@
116 , withObject
125 , withObject
Data/Aeson/Parser.hs+11−1
@@ -35,10 +35,20 @@ module Data.Aeson.Parser
35 , value
35 , value
36 , jstring
36 , jstring
37 , scientific
37 , scientific
38+ -- ** Handling objects with duplicate keys
39+ , jsonWith
40+ , jsonLast
41+ , jsonAccum
42+ , jsonNoDup
38 -- * Strict parsers
43 -- * Strict parsers
39 -- $strict
44 -- $strict
40 , json'
45 , json'
41 , value'
46 , value'
47+ -- ** Handling objects with duplicate keys
48+ , jsonWith'
49+ , jsonLast'
50+ , jsonAccum'
51+ , jsonNoDup'
42 -- * Decoding without FromJSON instances
52 -- * Decoding without FromJSON instances
43 , decodeWith
53 , decodeWith
44 , decodeStrictWith
54 , decodeStrictWith
@@ -47,7 +57,7 @@ module Data.Aeson.Parser
47 ) where
57 ) where
48
58
49
59
50−import Data.Aeson.Parser.Internal (decodeStrictWith, decodeWith, eitherDecodeStrictWith, eitherDecodeWith, json, json', jstring, scientific, value, value')
60+import Data.Aeson.Parser.Internal
51
61
52-- $lazy
62-- $lazy
53--
63--
Data/Aeson/Parser/Internal.hs+148−34
@@ -5,6 +5,10 @@
5#if MIN_VERSION_ghc_prim(0,3,1)
5#if MIN_VERSION_ghc_prim(0,3,1)
6{-# LANGUAGE MagicHash #-}
6{-# LANGUAGE MagicHash #-}
7#endif
7#endif
8+#if __GLASGOW_HASKELL__ <= 710 && __GLASGOW_HASKELL__ >= 706
9+-- Work around a compiler bug
10+{-# OPTIONS_GHC -fsimpl-tick-factor=200 #-}
11+#endif
8-- |
12-- |
9-- Module: Data.Aeson.Parser.Internal
13-- Module: Data.Aeson.Parser.Internal
10-- Copyright: (c) 2011-2016 Bryan O'Sullivan
14-- Copyright: (c) 2011-2016 Bryan O'Sullivan
@@ -21,30 +25,43 @@ module Data.Aeson.Parser.Internal
21 (
25 (
22 -- * Lazy parsers
26 -- * Lazy parsers
23 json, jsonEOF
27 json, jsonEOF
28+ , jsonWith
29+ , jsonLast
30+ , jsonAccum
31+ , jsonNoDup
24 , value
32 , value
25 , jstring
33 , jstring
26 , jstring_
34 , jstring_
27 , scientific
35 , scientific
28 -- * Strict parsers
36 -- * Strict parsers
29 , json', jsonEOF'
37 , json', jsonEOF'
38+ , jsonWith'
39+ , jsonLast'
40+ , jsonAccum'
41+ , jsonNoDup'
30 , value'
42 , value'
31 -- * Helpers
43 -- * Helpers
32 , decodeWith
44 , decodeWith
33 , decodeStrictWith
45 , decodeStrictWith
34 , eitherDecodeWith
46 , eitherDecodeWith
35 , eitherDecodeStrictWith
47 , eitherDecodeStrictWith
48+ -- ** Handling objects with duplicate keys
49+ , fromListAccum
50+ , parseListNoDup
36 ) where
51 ) where
37
52
38import Prelude.Compat
53import Prelude.Compat
39
54
40import Control.Applicative ((<|>))
55import Control.Applicative ((<|>))
41import Control.Monad (void, when)
56import Control.Monad (void, when)
42−import Data.Aeson.Types.Internal (IResult(..), JSONPath, Result(..), Value(..))
57+import Data.Aeson.Types.Internal (IResult(..), JSONPath, Object, Result(..), Value(..))
43import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, string)
58import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, string)
59+import Data.Function (fix)
44import Data.Functor.Compat (($>))
60import Data.Functor.Compat (($>))
45import Data.Scientific (Scientific)
61import Data.Scientific (Scientific)
46import Data.Text (Text)
62import Data.Text (Text)
63+import Data.Vector (Vector)
47−import Data.Vector as Vector (Vector, empty, fromListN, reverse)
64+import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
48import qualified Data.Attoparsec.ByteString as A
65import qualified Data.Attoparsec.ByteString as A
49import qualified Data.Attoparsec.Lazy as L
66import qualified Data.Attoparsec.Lazy as L
50import qualified Data.ByteString as B
67import qualified Data.ByteString as B
@@ -76,7 +93,7 @@ import qualified Data.Text.Encoding as TE
76#define C_n 110
93#define C_n 110
77#define C_t 116
94#define C_t 116
78
95
79−-- | Parse a top-level JSON value.
96+-- | Parse any JSON value.
80--
97--
81-- The conversion of a parsed value to a Haskell value is deferred
98-- The conversion of a parsed value to a Haskell value is deferred
82-- until the Haskell value is needed. This may improve performance if
99-- until the Haskell value is needed. This may improve performance if
@@ -86,10 +103,15 @@ import qualified Data.Text.Encoding as TE
86-- This function is an alias for 'value'. In aeson 0.8 and earlier, it
103-- This function is an alias for 'value'. In aeson 0.8 and earlier, it
87-- parsed only object or array types, in conformance with the
104-- parsed only object or array types, in conformance with the
88-- now-obsolete RFC 4627.
105-- now-obsolete RFC 4627.
106+--
107+-- ==== Warning
108+--
109+-- If an object contains duplicate keys, only the first one will be kept.
110+-- For a more flexible alternative, see 'jsonWith'.
89json :: Parser Value
111json :: Parser Value
90json = value
112json = value
91
113
92−-- | Parse a top-level JSON value.
114+-- | Parse any JSON value.
93--
115--
94-- This is a strict version of 'json' which avoids building up thunks
116-- This is a strict version of 'json' which avoids building up thunks
95-- during parsing; it performs all conversions immediately. Prefer
117-- during parsing; it performs all conversions immediately. Prefer
@@ -98,23 +120,35 @@ json = value
98-- This function is an alias for 'value''. In aeson 0.8 and earlier, it
120-- This function is an alias for 'value''. In aeson 0.8 and earlier, it
99-- parsed only object or array types, in conformance with the
121-- parsed only object or array types, in conformance with the
100-- now-obsolete RFC 4627.
122-- now-obsolete RFC 4627.
123+--
124+-- ==== Warning
125+--
126+-- If an object contains duplicate keys, only the first one will be kept.
127+-- For a more flexible alternative, see 'jsonWith''.
101json' :: Parser Value
128json' :: Parser Value
102json' = value'
129json' = value'
103
130
131+-- Open recursion: object_, object_', array_, array_' are parameterized by the
132+-- toplevel Value parser to be called recursively, to keep the parameter
133+-- mkObject outside of the recursive loop for proper inlining.
134+
104−object_ :: Parser Value
135+object_ :: ([(Text, Value)] -> Either String Object) -> Parser Value -> Parser Value
105−object_ = {-# SCC "object_" #-} Object <$> objectValues jstring value
136+object_ mkObject val = {-# SCC "object_" #-} Object <$> objectValues mkObject jstring val
137+{-# INLINE object_ #-}
106
138
107−object_' :: Parser Value
139+object_' :: ([(Text, Value)] -> Either String Object) -> Parser Value -> Parser Value
108−object_' = {-# SCC "object_'" #-} do
140+object_' mkObject val' = {-# SCC "object_'" #-} do
109− !vals <- objectValues jstring' value'
141+ !vals <- objectValues mkObject jstring' val'
110 return (Object vals)
142 return (Object vals)
111 where
143 where
112 jstring' = do
144 jstring' = do
113 !s <- jstring
145 !s <- jstring
114 return s
146 return s
147+{-# INLINE object_' #-}
115
148
149+objectValues :: ([(Text, Value)] -> Either String Object)
116−objectValues :: Parser Text -> Parser Value -> Parser (H.HashMap Text Value)
150+ -> Parser Text -> Parser Value -> Parser (H.HashMap Text Value)
117−objectValues str val = do
151+objectValues mkObject str val = do
118 skipSpace
152 skipSpace
119 w <- A.peekWord8'
153 w <- A.peekWord8'
120 if w == CLOSE_CURLY
154 if w == CLOSE_CURLY
@@ -130,16 +164,20 @@ objectValues str val = do
130 let acc' = (k, v) : acc
164 let acc' = (k, v) : acc
131 if ch == COMMA
165 if ch == COMMA
132 then skipSpace >> loop acc'
166 then skipSpace >> loop acc'
133− else return (H.fromList acc')
167+ else case mkObject acc' of
168+ Left err -> fail err
169+ Right obj -> pure obj
134{-# INLINE objectValues #-}
170{-# INLINE objectValues #-}
135
171
136−array_ :: Parser Value
172+array_ :: Parser Value -> Parser Value
137−array_ = {-# SCC "array_" #-} Array <$> arrayValues value
173+array_ val = {-# SCC "array_" #-} Array <$> arrayValues val
174+{-# INLINE array_ #-}
138
175
139−array_' :: Parser Value
176+array_' :: Parser Value -> Parser Value
140−array_' = {-# SCC "array_'" #-} do
177+array_' val = {-# SCC "array_'" #-} do
141− !vals <- arrayValues value'
178+ !vals <- arrayValues val
142 return (Array vals)
179 return (Array vals)
180+{-# INLINE array_' #-}
143
181
144arrayValues :: Parser Value -> Parser (Vector Value)
182arrayValues :: Parser Value -> Parser (Vector Value)
145arrayValues val = do
183arrayValues val = do
@@ -157,42 +195,104 @@ arrayValues val = do
157 else return (Vector.reverse (Vector.fromListN len (v:acc)))
195 else return (Vector.reverse (Vector.fromListN len (v:acc)))
158{-# INLINE arrayValues #-}
196{-# INLINE arrayValues #-}
159
197
160−-- | Parse any JSON value. You should usually 'json' in preference to
198+-- | Parse any JSON value. Synonym of 'json'.
161−-- this function, as this function relaxes the object-or-array
162−-- requirement of RFC 4627.
163−--
164−-- In particular, be careful in using this function if you think your
165−-- code might interoperate with Javascript. A na&#xef;ve Javascript
166−-- library that parses JSON data using @eval@ is vulnerable to attack
167−-- unless the encoded data represents an object or an array. JSON
168−-- implementations in other languages conform to that same restriction
169−-- to preserve interoperability and security.
170value :: Parser Value
199value :: Parser Value
171−value = do
200+value = jsonWith (pure . H.fromList)
201+
202+-- | Parse any JSON value.
203+--
204+-- This parser is parameterized by a function to construct an 'Object'
205+-- from a raw list of key-value pairs, where duplicates are preserved.
206+-- The pairs appear in __reverse order__ from the source.
207+--
208+-- ==== __Examples__
209+--
210+-- 'json' keeps only the first occurence of each key, using 'HashMap.Lazy.fromList'.
211+--
212+-- @
213+-- 'json' = 'jsonWith' ('Right' '.' 'H.fromList')
214+-- @
215+--
216+-- 'jsonLast' keeps the last occurence of each key, using
217+-- @'HashMap.Lazy.fromListWith' ('const' 'id')@.
218+--
219+-- @
220+-- 'jsonLast' = 'jsonWith' ('Right' '.' 'HashMap.Lazy.fromListWith' ('const' 'id'))
221+-- @
222+--
223+-- 'jsonAccum' keeps wraps all values in arrays to keep duplicates, using
224+-- 'fromListAccum'.
225+--
226+-- @
227+-- 'jsonAccum' = 'jsonWith' ('Right' . 'fromListAccum')
228+-- @
229+--
230+-- 'jsonNoDup' fails if any object contains duplicate keys, using 'parseListNoDup'.
231+--
232+-- @
233+-- 'jsonNoDup' = 'jsonWith' 'parseListNoDup'
234+-- @
235+jsonWith :: ([(Text, Value)] -> Either String Object) -> Parser Value
236+jsonWith mkObject = fix $ \value_ -> do
172 skipSpace
237 skipSpace
173 w <- A.peekWord8'
238 w <- A.peekWord8'
174 case w of
239 case w of
175 DOUBLE_QUOTE -> A.anyWord8 *> (String <$> jstring_)
240 DOUBLE_QUOTE -> A.anyWord8 *> (String <$> jstring_)
176− OPEN_CURLY -> A.anyWord8 *> object_
241+ OPEN_CURLY -> A.anyWord8 *> object_ mkObject value_
177− OPEN_SQUARE -> A.anyWord8 *> array_
242+ OPEN_SQUARE -> A.anyWord8 *> array_ value_
178 C_f -> string "false" $> Bool False
243 C_f -> string "false" $> Bool False
179 C_t -> string "true" $> Bool True
244 C_t -> string "true" $> Bool True
180 C_n -> string "null" $> Null
245 C_n -> string "null" $> Null
181 _ | w >= 48 && w <= 57 || w == 45
246 _ | w >= 48 && w <= 57 || w == 45
182 -> Number <$> scientific
247 -> Number <$> scientific
183 | otherwise -> fail "not a valid json value"
248 | otherwise -> fail "not a valid json value"
249+{-# INLINE jsonWith #-}
250+
251+-- | Variant of 'json' which keeps only the last occurence of every key.
252+jsonLast :: Parser Value
253+jsonLast = jsonWith (Right . H.fromListWith (const id))
254+
255+-- | Variant of 'json' wrapping all object mappings in 'Array' to preserve
256+-- key-value pairs with the same keys.
257+jsonAccum :: Parser Value
258+jsonAccum = jsonWith (Right . fromListAccum)
259+
260+-- | Variant of 'json' which fails if any object contains duplicate keys.
261+jsonNoDup :: Parser Value
262+jsonNoDup = jsonWith parseListNoDup
184
263
264+-- | @'fromListAccum' kvs@ is an object mapping keys to arrays containing all
265+-- associated values from the original list @kvs@.
266+--
267+-- >>> fromListAccum [("apple", Bool True), ("apple", Bool False), ("orange", Bool False)]
268+-- fromList [("apple", [Bool False, Bool True]), ("orange", [Bool False])]
269+fromListAccum :: [(Text, Value)] -> Object
270+fromListAccum =
271+ fmap (Array . Vector.fromList . ($ [])) . H.fromListWith (.) . (fmap . fmap) (:)
272+
273+-- | @'fromListNoDup' kvs@ fails if @kvs@ contains duplicate keys.
274+parseListNoDup :: [(Text, Value)] -> Either String Object
275+parseListNoDup =
276+ H.traverseWithKey unwrap . H.fromListWith (\_ _ -> Nothing) . (fmap . fmap) Just
277+ where
278+ unwrap k Nothing = Left $ "found duplicate key: " ++ show k
279+ unwrap _ (Just v) = Right v
280+
185−-- | Strict version of 'value'. See also 'json''.
281+-- | Strict version of 'value'. Synonym of 'json''.
186value' :: Parser Value
282value' :: Parser Value
187−value' = do
283+value' = jsonWith' (pure . H.fromList)
284+
285+-- | Strict version of 'jsonWith'.
286+jsonWith' :: ([(Text, Value)] -> Either String Object) -> Parser Value
287+jsonWith' mkObject = fix $ \value_ -> do
188 skipSpace
288 skipSpace
189 w <- A.peekWord8'
289 w <- A.peekWord8'
190 case w of
290 case w of
191 DOUBLE_QUOTE -> do
291 DOUBLE_QUOTE -> do
192 !s <- A.anyWord8 *> jstring_
292 !s <- A.anyWord8 *> jstring_
193 return (String s)
293 return (String s)
194− OPEN_CURLY -> A.anyWord8 *> object_'
294+ OPEN_CURLY -> A.anyWord8 *> object_' mkObject value_
195− OPEN_SQUARE -> A.anyWord8 *> array_'
295+ OPEN_SQUARE -> A.anyWord8 *> array_' value_
196 C_f -> string "false" $> Bool False
296 C_f -> string "false" $> Bool False
197 C_t -> string "true" $> Bool True
297 C_t -> string "true" $> Bool True
198 C_n -> string "null" $> Null
298 C_n -> string "null" $> Null
@@ -201,6 +301,20 @@ value' = do
201 !n <- scientific
301 !n <- scientific
202 return (Number n)
302 return (Number n)
203 | otherwise -> fail "not a valid json value"
303 | otherwise -> fail "not a valid json value"
304+{-# INLINE jsonWith' #-}
305+
306+-- | Variant of 'json'' which keeps only the last occurence of every key.
307+jsonLast' :: Parser Value
308+jsonLast' = jsonWith' (pure . H.fromListWith (const id))
309+
310+-- | Variant of 'json'' wrapping all object mappings in 'Array' to preserve
311+-- key-value pairs with the same keys.
312+jsonAccum' :: Parser Value
313+jsonAccum' = jsonWith' (pure . fromListAccum)
314+
315+-- | Variant of 'json'' which fails if any object contains duplicate keys.
316+jsonNoDup' :: Parser Value
317+jsonNoDup' = jsonWith' parseListNoDup
204
318
205-- | Parse a quoted JSON string.
319-- | Parse a quoted JSON string.
206jstring :: Parser Text
320jstring :: Parser Text
Data/Aeson/Types.hs+16
@@ -53,6 +53,12 @@ module Data.Aeson.Types
53 , coerceFromJSONKeyFunction
53 , coerceFromJSONKeyFunction
54 , mapFromJSONKeyFunction
54 , mapFromJSONKeyFunction
55
55
56+ -- *** Generic keys
57+ , GToJSONKey()
58+ , genericToJSONKey
59+ , GFromJSONKey()
60+ , genericFromJSONKey
61+
56 -- ** Liftings to unary and binary type constructors
62 -- ** Liftings to unary and binary type constructors
57 , FromJSON1(..)
63 , FromJSON1(..)
58 , parseJSON1
64 , parseJSON1
@@ -125,6 +131,16 @@ module Data.Aeson.Types
125 , camelTo2
131 , camelTo2
126 , defaultOptions
132 , defaultOptions
127 , defaultTaggedObject
133 , defaultTaggedObject
134+
135+ -- ** Options for object keys
136+ , JSONKeyOptions
137+ , keyModifier
138+ , defaultJSONKeyOptions
139+
140+ -- * Parsing context
141+ , (<?>)
142+ , JSONPath
143+ , JSONPathElement(..)
128 ) where
144 ) where
129
145
130import Prelude.Compat
146import Prelude.Compat
Data/Aeson/Types/Class.hs+5
@@ -58,6 +58,11 @@ module Data.Aeson.Types.Class
58 , fromJSONKeyCoerce
58 , fromJSONKeyCoerce
59 , coerceFromJSONKeyFunction
59 , coerceFromJSONKeyFunction
60 , mapFromJSONKeyFunction
60 , mapFromJSONKeyFunction
61+ -- ** Generic keys
62+ , GToJSONKey()
63+ , genericToJSONKey
64+ , GFromJSONKey()
65+ , genericFromJSONKey
61 -- * Object key-value pairs
66 -- * Object key-value pairs
62 , KeyValue(..)
67 , KeyValue(..)
63
68
Data/Aeson/Types/FromJSON.hs+69−17
@@ -5,7 +5,6 @@
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE GADTs #-}
6{-# LANGUAGE GADTs #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE NamedFieldPuns #-}
9{-# LANGUAGE NoImplicitPrelude #-}
8{-# LANGUAGE NoImplicitPrelude #-}
10{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE OverloadedStrings #-}
11{-# LANGUAGE RecordWildCards #-}
10{-# LANGUAGE RecordWildCards #-}
@@ -45,6 +44,9 @@ module Data.Aeson.Types.FromJSON
45 , coerceFromJSONKeyFunction
44 , coerceFromJSONKeyFunction
46 , mapFromJSONKeyFunction
45 , mapFromJSONKeyFunction
47
46
47+ , GFromJSONKey()
48+ , genericFromJSONKey
49+
48 -- * List functions
50 -- * List functions
49 , listParser
51 , listParser
50
52
@@ -406,6 +408,16 @@ class FromJSON a where
406-- > newtype SomeId = SomeId { getSomeId :: Text }
408-- > newtype SomeId = SomeId { getSomeId :: Text }
407-- > deriving (Eq,Ord,Hashable,FromJSONKey)
409-- > deriving (Eq,Ord,Hashable,FromJSONKey)
408--
410--
411+-- If you have a sum of nullary constructors, you may use the generic
412+-- implementation:
413+--
414+-- @
415+-- data Color = Red | Green | Blue
416+-- deriving Generic
417+--
418+-- instance 'FromJSONKey' Color where
419+-- 'fromJSONKey' = 'genericFromJSONKey' 'defaultJSONKeyOptions'
420+-- @
409class FromJSONKey a where
421class FromJSONKey a where
410 -- | Strategy for parsing the key of a map-like container.
422 -- | Strategy for parsing the key of a map-like container.
411 fromJSONKey :: FromJSONKeyFunction a
423 fromJSONKey :: FromJSONKeyFunction a
@@ -504,6 +516,35 @@ coerceFromJSONKeyFunction (FromJSONKeyValue f) = FromJSONKeyValue (fma
504mapFromJSONKeyFunction :: (a -> b) -> FromJSONKeyFunction a -> FromJSONKeyFunction b
516mapFromJSONKeyFunction :: (a -> b) -> FromJSONKeyFunction a -> FromJSONKeyFunction b
505mapFromJSONKeyFunction = fmap
517mapFromJSONKeyFunction = fmap
506
518
519+-- | 'fromJSONKey' for 'Generic' types.
520+-- These types must be sums of nullary constructors, whose names will be used
521+-- as keys for JSON objects.
522+--
523+-- See also 'genericToJSONKey'.
524+--
525+-- === __Example__
526+--
527+-- @
528+-- data Color = Red | Green | Blue
529+-- deriving 'Generic'
530+--
531+-- instance 'FromJSONKey' Color where
532+-- 'fromJSONKey' = 'genericFromJSONKey' 'defaultJSONKeyOptions'
533+-- @
534+genericFromJSONKey :: forall a. (Generic a, GFromJSONKey (Rep a))
535+ => JSONKeyOptions
536+ -> FromJSONKeyFunction a
537+genericFromJSONKey opts = FromJSONKeyTextParser $ \t ->
538+ case parseSumFromString (keyModifier opts) t of
539+ Nothing -> fail $
540+ "invalid key " ++ show t ++ ", expected one of " ++ show cnames
541+ Just k -> pure (to k)
542+ where
543+ cnames = unTagged2 (constructorTags (keyModifier opts) :: Tagged2 (Rep a) [String])
544+
545+class (ConstructorNames f, SumFromString f) => GFromJSONKey f where
546+instance (ConstructorNames f, SumFromString f) => GFromJSONKey f where
547+
507-------------------------------------------------------------------------------
548-------------------------------------------------------------------------------
508-- Functions needed for documentation
549-- Functions needed for documentation
509-------------------------------------------------------------------------------
550-------------------------------------------------------------------------------
@@ -1034,41 +1075,46 @@ parseAllNullarySum :: (SumFromString f, ConstructorNames f)
1034parseAllNullarySum tname opts =
1075parseAllNullarySum tname opts =
1035 withText tname $ \tag ->
1076 withText tname $ \tag ->
1036 maybe (badTag tag) return $
1077 maybe (badTag tag) return $
1037− parseSumFromString opts tag
1078+ parseSumFromString modifier tag
1038 where
1079 where
1039− badTag tag = failWithCTags tname opts $ \cnames ->
1080+ badTag tag = failWithCTags tname modifier $ \cnames ->
1040 "expected one of the tags " ++ show cnames ++
1081 "expected one of the tags " ++ show cnames ++
1041 ", but found tag " ++ show tag
1082 ", but found tag " ++ show tag
1083+ modifier = constructorTagModifier opts
1042
1084
1043-- | Fail with an informative error message about a mismatched tag.
1085-- | Fail with an informative error message about a mismatched tag.
1044-- The error message is parameterized by the list of expected tags,
1086-- The error message is parameterized by the list of expected tags,
1045-- to be inferred from the result type of the parser.
1087-- to be inferred from the result type of the parser.
1046failWithCTags
1088failWithCTags
1047− :: forall f a. ConstructorNames f
1089+ :: forall f a t. ConstructorNames f
1048− => TypeName -> Options -> ([String] -> String) -> Parser (f a)
1090+ => TypeName -> (String -> t) -> ([t] -> String) -> Parser (f a)
1049−failWithCTags tname opts f =
1091+failWithCTags tname modifier f =
1050 contextType tname . fail $ f cnames
1092 contextType tname . fail $ f cnames
1051 where
1093 where
1052− cnames = unTagged2 (constructorTags opts :: Tagged2 f [String])
1094+ cnames = unTagged2 (constructorTags modifier :: Tagged2 f [t])
1053
1095
1054class SumFromString f where
1096class SumFromString f where
1055− parseSumFromString :: Options -> Text -> Maybe (f a)
1097+ parseSumFromString :: (String -> String) -> Text -> Maybe (f a)
1056
1098
1057instance (SumFromString a, SumFromString b) => SumFromString (a :+: b) where
1099instance (SumFromString a, SumFromString b) => SumFromString (a :+: b) where
1058 parseSumFromString opts key = (L1 <$> parseSumFromString opts key) <|>
1100 parseSumFromString opts key = (L1 <$> parseSumFromString opts key) <|>
1059 (R1 <$> parseSumFromString opts key)
1101 (R1 <$> parseSumFromString opts key)
1060
1102
1061instance (Constructor c) => SumFromString (C1 c U1) where
1103instance (Constructor c) => SumFromString (C1 c U1) where
1062− parseSumFromString opts key | key == name = Just $ M1 U1
1104+ parseSumFromString modifier key
1105+ | key == name = Just $ M1 U1
1063− | otherwise = Nothing
1106+ | otherwise = Nothing
1064− where
1107+ where
1065− name = pack $ constructorTagModifier opts $
1066− conName (undefined :: M1 _i c _f _p)
1108+ name = pack $ modifier $ conName (undefined :: M1 _i c _f _p)
1109+
1110+-- For genericFromJSONKey
1111+instance SumFromString a => SumFromString (D1 d a) where
1112+ parseSumFromString modifier key = M1 <$> parseSumFromString modifier key
1067
1113
1068-- | List of all constructor tags.
1114-- | List of all constructor tags.
1069−constructorTags :: ConstructorNames a => Options -> Tagged2 a [String]
1115+constructorTags :: ConstructorNames a => (String -> t) -> Tagged2 a [t]
1070−constructorTags opts =
1116+constructorTags modifier =
1071− fmap DList.toList (constructorNames' (constructorTagModifier opts))
1117+ fmap DList.toList (constructorNames' modifier)
1072
1118
1073-- | List of all constructor names of an ADT, after a given conversion
1119-- | List of all constructor names of an ADT, after a given conversion
1074-- function. (Better inlining.)
1120-- function. (Better inlining.)
@@ -1089,6 +1135,12 @@ instance Constructor c => ConstructorNames (C1 c a) where
1089 where
1135 where
1090 cname = conName (undefined :: M1 _i c _f _p)
1136 cname = conName (undefined :: M1 _i c _f _p)
1091
1137
1138+-- For genericFromJSONKey
1139+instance ConstructorNames a => ConstructorNames (D1 d a) where
1140+ constructorNames' = retag . constructorNames'
1141+ where
1142+ retag :: Tagged2 a u -> Tagged2 (D1 d a) u
1143+ retag (Tagged2 x) = Tagged2 x
1092
1144
1093--------------------------------------------------------------------------------
1145--------------------------------------------------------------------------------
1094parseNonAllNullarySum :: forall f c arity.
1146parseNonAllNullarySum :: forall f c arity.
@@ -1144,7 +1196,7 @@ parseNonAllNullarySum p@(tname :* opts :* _) =
1144
1196
1145 UntaggedValue -> parseUntaggedValue p
1197 UntaggedValue -> parseUntaggedValue p
1146 where
1198 where
1147− failWith_ = failWithCTags tname opts
1199+ failWith_ = failWithCTags tname (constructorTagModifier opts)
1148
1200
1149--------------------------------------------------------------------------------
1201--------------------------------------------------------------------------------
1150
1202
Data/Aeson/Types/Internal.hs+76−3
@@ -65,8 +65,10 @@ module Data.Aeson.Types.Internal
65 )
65 )
66
66
67 , SumEncoding(..)
67 , SumEncoding(..)
68+ , JSONKeyOptions(keyModifier)
68 , defaultOptions
69 , defaultOptions
69 , defaultTaggedObject
70 , defaultTaggedObject
71+ , defaultJSONKeyOptions
70
72
71 -- * Used for changing CamelCase names into something else.
73 -- * Used for changing CamelCase names into something else.
72 , camelTo
74 , camelTo
@@ -97,6 +99,7 @@ import Data.Time.Format (FormatTime)
97import Data.Typeable (Typeable)
99import Data.Typeable (Typeable)
98import Data.Vector (Vector)
100import Data.Vector (Vector)
99import GHC.Generics (Generic)
101import GHC.Generics (Generic)
102+import qualified Control.Monad as Monad
100import qualified Control.Monad.Fail as Fail
103import qualified Control.Monad.Fail as Fail
101import qualified Data.HashMap.Strict as H
104import qualified Data.HashMap.Strict as H
102import qualified Data.Scientific as S
105import qualified Data.Scientific as S
@@ -150,7 +153,7 @@ instance Functor Result where
150 fmap _ (Error err) = Error err
153 fmap _ (Error err) = Error err
151 {-# INLINE fmap #-}
154 {-# INLINE fmap #-}
152
155
153−instance Monad IResult where
156+instance Monad.Monad IResult where
154 return = pure
157 return = pure
155 {-# INLINE return #-}
158 {-# INLINE return #-}
156
159
@@ -167,7 +170,7 @@ instance Fail.MonadFail IResult where
167 fail err = IError [] err
170 fail err = IError [] err
168 {-# INLINE fail #-}
171 {-# INLINE fail #-}
169
172
170−instance Monad Result where
173+instance Monad.Monad Result where
171 return = pure
174 return = pure
172 {-# INLINE return #-}
175 {-# INLINE return #-}
173
176
@@ -286,7 +289,7 @@ newtype Parser a = Parser {
286 -> f r
289 -> f r
287 }
290 }
288
291
289−instance Monad Parser where
292+instance Monad.Monad Parser where
290 m >>= g = Parser $ \path kf ks -> let ks' a = runParser (g a) path kf ks
293 m >>= g = Parser $ \path kf ks -> let ks' a = runParser (g a) path kf ks
291 in runParser m path kf ks'
294 in runParser m path kf ks'
292 {-# INLINE (>>=) #-}
295 {-# INLINE (>>=) #-}
@@ -568,6 +571,39 @@ data Options = Options
568 -- ^ If 'True' record fields with a 'Nothing' value will be
571 -- ^ If 'True' record fields with a 'Nothing' value will be
569 -- omitted from the resulting object. If 'False' the resulting
572 -- omitted from the resulting object. If 'False' the resulting
570 -- object will include those fields mapping to @null@.
573 -- object will include those fields mapping to @null@.
574+ --
575+ -- === Note
576+ --
577+ -- Setting 'omitNothingFields' to 'True' only affects fields which are of
578+ -- type 'Maybe' /uniformly/ in the 'ToJSON' or 'FromJSON' instance. In
579+ -- particular, if the type of a field is declared as a type variable, it
580+ -- will not be omitted from the JSON object, unless the field is
581+ -- specialized upfront in the instance.
582+ --
583+ -- ==== __Example__
584+ --
585+ -- The generic instance for the following type @Fruit@ depends on whether
586+ -- the instance head is @Fruit a@ or @Fruit (Maybe a)@.
587+ --
588+ -- @
589+ -- data Fruit a =
590+ -- { apples :: a -- A field whose type is a type variable.
591+ -- , oranges :: 'Maybe' Int
592+ -- }
593+ --
594+ -- options :: 'Options'
595+ -- options = 'defaultOptions' { 'omitNothingFields' = 'True' }
596+ --
597+ -- -- apples required, oranges optional
598+ -- -- Even if 'Data.Aeson.fromJSON' is then specialized to (Fruit ('Maybe' a)).
599+ -- instance 'Data.Aeson.FromJSON' a => 'Data.Aeson.FromJSON' (Fruit a) where
600+ -- 'Data.Aeson.fromJSON' = 'Data.Aeson.genericFromJSON' options
601+ --
602+ -- -- apples optional, oranges optional
603+ -- -- In this instance, the field apples is uniformly of type ('Maybe' a).
604+ -- instance 'Data.Aeson.FromJSON' a => 'Data.Aeson.FromJSON' (Fruit ('Maybe' a)) where
605+ -- 'Data.Aeson.fromJSON' = 'Data.Aeson.genericFromJSON' options
606+ -- @
571 , sumEncoding :: SumEncoding
607 , sumEncoding :: SumEncoding
572 -- ^ Specifies how to encode constructors of a sum datatype.
608 -- ^ Specifies how to encode constructors of a sum datatype.
573 , unwrapUnaryRecords :: Bool
609 , unwrapUnaryRecords :: Bool
@@ -632,6 +668,33 @@ data SumEncoding =
632 -- contents of the constructor.
668 -- contents of the constructor.
633 deriving (Eq, Show)
669 deriving (Eq, Show)
634
670
671+-- | Options for encoding keys with 'Data.Aeson.Types.genericFromJSONKey' and
672+-- 'Data.Aeson.Types.genericToJSONKey'.
673+data JSONKeyOptions = JSONKeyOptions
674+ { keyModifier :: String -> String
675+ -- ^ Function applied to keys. Its result is what goes into the encoded
676+ -- 'Value'.
677+ --
678+ -- === __Example__
679+ --
680+ -- The following instances encode the constructor @Bar@ to lower-case keys
681+ -- @\"bar\"@.
682+ --
683+ -- @
684+ -- data Foo = Bar
685+ -- deriving 'Generic'
686+ --
687+ -- opts :: 'JSONKeyOptions'
688+ -- opts = 'defaultJSONKeyOptions' { 'keyModifier' = 'toLower' }
689+ --
690+ -- instance 'ToJSONKey' Foo where
691+ -- 'toJSONKey' = 'genericToJSONKey' opts
692+ --
693+ -- instance 'FromJSONKey' Foo where
694+ -- 'fromJSONKey' = 'genericFromJSONKey' opts
695+ -- @
696+ }
697+
635-- | Default encoding 'Options':
698-- | Default encoding 'Options':
636--
699--
637-- @
700-- @
@@ -670,6 +733,16 @@ defaultTaggedObject = TaggedObject
670 , contentsFieldName = "contents"
733 , contentsFieldName = "contents"
671 }
734 }
672
735
736+-- | Default 'JSONKeyOptions':
737+--
738+-- @
739+-- defaultJSONKeyOptions = 'JSONKeyOptions'
740+-- { 'keyModifier' = 'id'
741+-- }
742+-- @
743+defaultJSONKeyOptions :: JSONKeyOptions
744+defaultJSONKeyOptions = JSONKeyOptions id
745+
673-- | Converts from CamelCase to another lower case, interspersing
746-- | Converts from CamelCase to another lower case, interspersing
674-- the character between all capital letters and their previous
747-- the character between all capital letters and their previous
675-- entries, except those capital letters that appear together,
748-- entries, except those capital letters that appear together,
Data/Aeson/Types/ToJSON.hs+43−4
@@ -5,7 +5,6 @@
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE FunctionalDependencies #-}
6{-# LANGUAGE FunctionalDependencies #-}
7{-# LANGUAGE GADTs #-}
7{-# LANGUAGE GADTs #-}
8−{-# LANGUAGE NamedFieldPuns #-}
9{-# LANGUAGE NoImplicitPrelude #-}
8{-# LANGUAGE NoImplicitPrelude #-}
10{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE OverloadedStrings #-}
11{-# LANGUAGE PatternGuards #-}
10{-# LANGUAGE PatternGuards #-}
@@ -47,6 +46,10 @@ module Data.Aeson.Types.ToJSON
47 , ToJSONKeyFunction(..)
46 , ToJSONKeyFunction(..)
48 , toJSONKeyText
47 , toJSONKeyText
49 , contramapToJSONKeyFunction
48 , contramapToJSONKeyFunction
49+
50+ , GToJSONKey()
51+ , genericToJSONKey
52+
50 -- * Object key-value pairs
53 -- * Object key-value pairs
51 , KeyValue(..)
54 , KeyValue(..)
52 , KeyValuePair(..)
55 , KeyValuePair(..)
@@ -411,7 +414,7 @@ instance KeyValue Object where
411-- newtype wrapper around 'Text'. The recommended approach is to use
414-- newtype wrapper around 'Text'. The recommended approach is to use
412-- generalized newtype deriving:
415-- generalized newtype deriving:
413--
416--
414−-- > newtype RecordId = RecordId { getRecordId :: Text}
417+-- > newtype RecordId = RecordId { getRecordId :: Text }
415-- > deriving (Eq,Ord,ToJSONKey)
418-- > deriving (Eq,Ord,ToJSONKey)
416--
419--
417-- Then we may write:
420-- Then we may write:
@@ -426,8 +429,18 @@ instance KeyValue Object where
426--
429--
427-- It is possible to get the 'ToJSONKey' instance for free as we did
430-- It is possible to get the 'ToJSONKey' instance for free as we did
428-- with 'Foo'. However, in this case, we have a natural way to go to
431-- with 'Foo'. However, in this case, we have a natural way to go to
429−-- and from 'Text' that does not require any escape sequences. So, in
432+-- and from 'Text' that does not require any escape sequences. So
430−-- this example, 'ToJSONKeyText' will be used instead of 'ToJSONKeyValue'.
433+-- 'ToJSONKeyText' can be used instead of 'ToJSONKeyValue' to encode maps
434+-- as objects instead of arrays of pairs. This instance may be
435+-- implemented using generics as follows:
436+--
437+-- @
438+-- instance 'ToJSONKey' Color where
439+-- 'toJSONKey' = 'genericToJSONKey' 'defaultJSONKeyOptions'
440+-- @
441+--
442+-- === __Low-level implementations__
443+--
431-- The 'Show' instance can be used to help write 'ToJSONKey':
444-- The 'Show' instance can be used to help write 'ToJSONKey':
432--
445--
433-- > instance ToJSONKey Color where
446-- > instance ToJSONKey Color where
@@ -515,6 +528,29 @@ contramapToJSONKeyFunction h x = case x of
515 ToJSONKeyText f g -> ToJSONKeyText (f . h) (g . h)
528 ToJSONKeyText f g -> ToJSONKeyText (f . h) (g . h)
516 ToJSONKeyValue f g -> ToJSONKeyValue (f . h) (g . h)
529 ToJSONKeyValue f g -> ToJSONKeyValue (f . h) (g . h)
517
530
531+-- 'toJSONKey' for 'Generic' types.
532+-- Deriving is supported for enumeration types, i.e. the sums of nullary
533+-- constructors. The names of constructors will be used as keys for JSON
534+-- objects.
535+--
536+-- See also 'genericFromJSONKey'.
537+--
538+-- === __Example__
539+--
540+-- @
541+-- data Color = Red | Green | Blue
542+-- deriving 'Generic'
543+--
544+-- instance 'ToJSONKey' Color where
545+-- 'toJSONKey' = 'genericToJSONKey' 'defaultJSONKeyOptions'
546+-- @
547+genericToJSONKey :: (Generic a, GToJSONKey (Rep a))
548+ => JSONKeyOptions -> ToJSONKeyFunction a
549+genericToJSONKey opts = toJSONKeyText (pack . keyModifier opts . getConName . from)
550+
551+class GetConName f => GToJSONKey f
552+instance GetConName f => GToJSONKey f
553+
518-------------------------------------------------------------------------------
554-------------------------------------------------------------------------------
519-- Lifings of FromJSON and ToJSON to unary and binary type constructors
555-- Lifings of FromJSON and ToJSON to unary and binary type constructors
520-------------------------------------------------------------------------------
556-------------------------------------------------------------------------------
@@ -944,6 +980,9 @@ instance (GetConName a, GetConName b) => GetConName (a :+: b) where
944instance (Constructor c) => GetConName (C1 c a) where
980instance (Constructor c) => GetConName (C1 c a) where
945 getConName = conName
981 getConName = conName
946
982
983+-- For genericToJSONKey
984+instance GetConName a => GetConName (D1 d a) where
985+ getConName (M1 x) = getConName x
947
986
948--------------------------------------------------------------------------------
987--------------------------------------------------------------------------------
949
988
Makefile+1−1
@@ -1,2 +1,2 @@
1lint:
1lint:
2− hlint --cpp-include include/ --cpp-file .stack-work/dist/*/*Cabal-*/build/autogen/cabal_macros.h Data/ attoparsec-iso8601/ benchmarks/ examples/ ffi/ pure/ tests/
2+ ./run-hlint.sh --cpp-include include/ --cpp-file travis/cabal_macros.h Data/ attoparsec-iso8601/ benchmarks/ examples/ ffi/ pure/ tests/
aeson.cabal+4−5
@@ -1,5 +1,5 @@
1name: aeson
1name: aeson
2−version: 1.4.3.0
2+version: 1.4.5.0
3license: BSD3
3license: BSD3
4license-file: LICENSE
4license-file: LICENSE
5category: Text, Web, JSON
5category: Text, Web, JSON
@@ -107,16 +107,16 @@ library
107 containers >= 0.4.2.1 && < 0.7,
107 containers >= 0.4.2.1 && < 0.7,
108 deepseq >= 1.3.0.0 && < 1.5,
108 deepseq >= 1.3.0.0 && < 1.5,
109 ghc-prim >= 0.2 && < 0.6,
109 ghc-prim >= 0.2 && < 0.6,
110− template-haskell >= 2.7.0.0 && < 2.15,
110+ template-haskell >= 2.7.0.0 && < 2.16,
111 text >= 1.2.3.0 && < 1.3,
111 text >= 1.2.3.0 && < 1.3,
112− time >= 1.4 && < 1.9
112+ time >= 1.4 && < 1.10
113
113
114 if impl(ghc >= 8.0)
114 if impl(ghc >= 8.0)
115 build-depends: bytestring >= 0.10.8.1
115 build-depends: bytestring >= 0.10.8.1
116
116
117 -- Compat
117 -- Compat
118 build-depends:
118 build-depends:
119− base-compat >= 0.9.1 && < 0.11,
119+ base-compat >= 0.9.1 && < 0.12,
120 time-compat >= 1.9.2.2 && < 1.10
120 time-compat >= 1.9.2.2 && < 1.10
121
121
122 if flag(bytestring-builder)
122 if flag(bytestring-builder)
@@ -157,7 +157,6 @@ library
157 hashable >= 1.2.7.0 && < 1.4,
157 hashable >= 1.2.7.0 && < 1.4,
158 scientific >= 0.3.6.2 && < 0.4,
158 scientific >= 0.3.6.2 && < 0.4,
159 th-abstraction >= 0.2.8.0 && < 0.4,
159 th-abstraction >= 0.2.8.0 && < 0.4,
160− time-locale-compat >= 0.1.1.5 && < 0.2,
161 uuid-types >= 1.0.3 && < 1.1,
160 uuid-types >= 1.0.3 && < 1.1,
162 vector >= 0.12.0.1 && < 0.13
161 vector >= 0.12.0.1 && < 0.13
163
162
attoparsec-iso8601/attoparsec-iso8601.cabal+1−1
@@ -37,7 +37,7 @@ library
37 build-depends:
37 build-depends:
38 attoparsec >= 0.13.0.1,
38 attoparsec >= 0.13.0.1,
39 base >= 4.5 && < 5,
39 base >= 4.5 && < 5,
40− base-compat >= 0.9.1 && < 0.11,
40+ base-compat >= 0.9.1 && < 0.12,
41 text >= 1.1.1.0,
41 text >= 1.1.1.0,
42 time >= 1.1.1.4
42 time >= 1.1.1.4
43
43
benchmarks/AesonEncode.hs+1−1
@@ -7,7 +7,7 @@ module Main (main) where
7import Prelude.Compat
7import Prelude.Compat
8
8
9import Control.DeepSeq
9import Control.DeepSeq
10−import Control.Monad
10+import Control.Monad (forM_)
11import Data.Aeson
11import Data.Aeson
12import Data.Attoparsec.ByteString (IResult(..), parseWith)
12import Data.Attoparsec.ByteString (IResult(..), parseWith)
13import Data.Char (isDigit)
13import Data.Char (isDigit)
benchmarks/Compare/JsonBench.hs+2−1
@@ -20,6 +20,7 @@ import Data.Aeson ((.:))
20import Data.Monoid ((<>))
20import Data.Monoid ((<>))
21import Data.Text (Text)
21import Data.Text (Text)
22import Typed.Common (load)
22import Typed.Common (load)
23+import qualified Control.Monad.Fail as Fail
23import qualified Data.Aeson as Aeson
24import qualified Data.Aeson as Aeson
24import qualified Data.BufferBuilder.Json as Json
25import qualified Data.BufferBuilder.Json as Json
25
26
@@ -82,7 +83,7 @@ genderTable = [("male", Male), ("female", Female)]
82fruitTable :: [(Text, Fruit)]
83fruitTable :: [(Text, Fruit)]
83fruitTable = [("apple", Apple), ("strawberry", Strawberry), ("banana", Banana)]
84fruitTable = [("apple", Apple), ("strawberry", Strawberry), ("banana", Banana)]
84
85
85−enumFromJson :: Monad m => String -> [(Text, enum)] -> (json -> m Text) -> json -> m enum
86+enumFromJson :: Fail.MonadFail m => String -> [(Text, enum)] -> (json -> m Text) -> json -> m enum
86enumFromJson enumName table extract v = do
87enumFromJson enumName table extract v = do
87 s <- extract v
88 s <- extract v
88 case lookup s table of
89 case lookup s table of
benchmarks/Issue673.hs+1
@@ -18,6 +18,7 @@ import Criterion.Main
18import Prelude.Compat
18import Prelude.Compat
19import Data.Int (Int64)
19import Data.Int (Int64)
20import Data.Scientific (Scientific)
20import Data.Scientific (Scientific)
21+import Data.Semigroup ((<>))
21import Data.Aeson.Parser (scientific)
22import Data.Aeson.Parser (scientific)
22
23
23import qualified Data.Attoparsec.ByteString.Lazy as AttoL
24import qualified Data.Attoparsec.ByteString.Lazy as AttoL
benchmarks/aeson-benchmarks.cabal+7
@@ -176,6 +176,9 @@ executable aeson-benchmark-compare
176 Compare.JsonBuilder
176 Compare.JsonBuilder
177 build-depends:
177 build-depends:
178 json-builder
178 json-builder
179+ if impl(ghc < 8.0)
180+ build-depends:
181+ semigroups
179
182
180executable aeson-benchmark-micro
183executable aeson-benchmark-micro
181 default-language: Haskell2010
184 default-language: Haskell2010
@@ -222,6 +225,8 @@ executable aeson-benchmark-typed
222 bytestring-builder >= 0.10.4 && < 1
225 bytestring-builder >= 0.10.4 && < 1
223 else
226 else
224 build-depends: bytestring >= 0.10.4
227 build-depends: bytestring >= 0.10.4
228+ if impl(ghc < 8.0)
229+ build-depends: semigroups
225
230
226executable aeson-benchmark-compare-with-json
231executable aeson-benchmark-compare-with-json
227 default-language: Haskell2010
232 default-language: Haskell2010
@@ -337,3 +342,5 @@ executable aeson-issue-673
337 scientific,
342 scientific,
338 base-compat,
343 base-compat,
339 criterion >= 1.0
344 criterion >= 1.0
345+ if impl(ghc < 8.0)
346+ build-depends: semigroups
cabal.project+2−1
@@ -1,3 +1,4 @@
1with-compiler: ghc
1with-compiler: ghc
2packages: .
2packages: .
3−packages: attoparsec-iso8601, benchmarks
3+packages: attoparsec-iso8601
4+-- packages: benchmarks
changelog.md+43
@@ -1,5 +1,48 @@
1For the latest version of this document, please see [https://github.com/bos/aeson/blob/master/changelog.md](https://github.com/bos/aeson/blob/master/changelog.md).
1For the latest version of this document, please see [https://github.com/bos/aeson/blob/master/changelog.md](https://github.com/bos/aeson/blob/master/changelog.md).
2
2
3+### 1.4.5.0
4+
5+* Expose `(<?>)`, `JSONPath` and `JSONPathElement(..)` from `Data.Aeson.Types`. Previously only available through internal modules. Thanks to Luke Clifton.
6+
7+* Support for base-compat 0.11, thanks to Ryan Scott.
8+
9+* Travis build for GHC 8.8, thanks to Oleg Grenrus.
10+
11+### 1.4.4.0
12+
13+**New features**:
14+
15+* Adds a parameterized parser `jsonWith` that can be used to choose how to handle duplicate keys in objects, thanks to Xia Li-Yao.
16+
17+* Add generic implementations of `FromJSONKey` and `ToJSONKey`, thanks to Xia Li-Yao. Example:
18+
19+```haskell
20+data Foo = Bar
21+ deriving Generic
22+
23+opts :: JSONKeyOptions
24+opts = defaultJSONKeyOptions { keyModifier = toLower }
25+
26+instance ToJSONKey Foo where
27+ toJSONKey = genericToJSONKey opts
28+
29+instance FromJSONKey Foo where
30+ fromJSONKey = genericFromJSONKey opts
31+```
32+
33+**Minor**:
34+* aeson now uses `time-compat` instead of `time-locale-compat`, thanks to Oleg Grenrus.
35+* Prepare for `MonadFail` breakages in GHC 8.8, thanks to Oleg Grenrus.
36+* Require `bytestring >= 0.10.8.1` for newer GHCs to avoid build failures, thanks to Oleg Grenrus.
37+* Support `primitive 0.7.*`, thanks to Adam Bergmark.
38+* Allow `semigroups 0.19.*` and `hashable 1.3.*`, thanks to Oleg Grenrus.
39+* Fix a typo in the error message when parsing `NonEmpty`, thanks to Colin Woodbury.
40+* Document surprising behavior when using `omitNothingFields` with type variables, thanks to Xia Li-Yao.
41+
42+**Internal changes**:
43+* Code cleanup by Oleg Grenrus
44+* Fix dependencies of the benchmarks on older GHC's, thanks to Xia Li-Yao.
45+
3### 1.4.3.0
46### 1.4.3.0
4* Improve error messages for FromJSON in existing instances and GHC Generic implementation. Thanks to Xia Li-Yao & Igor Pashev.
47* Improve error messages for FromJSON in existing instances and GHC Generic implementation. Thanks to Xia Li-Yao & Igor Pashev.
5* Tweak error-reporting combinators and their documentation. Thanks to Xia Li-Yao.
48* Tweak error-reporting combinators and their documentation. Thanks to Xia Li-Yao.
run-hlint.shnew file+7
@@ -0,0 +1,7 @@
1+#!/bin/bash
2+
3+if hash hlint 2>/dev/null; then
4+ hlint "$@"
5+else
6+ ./hlint.sh "$@"
7+fi
tests/Encoders.hs+13
@@ -6,6 +6,7 @@
6module Encoders (module Encoders) where
6module Encoders (module Encoders) where
7
7
8import Prelude.Compat
8import Prelude.Compat
9+import Data.Text (Text)
9
10
10import Data.Aeson.TH
11import Data.Aeson.TH
11import Data.Aeson.Types
12import Data.Aeson.Types
@@ -96,6 +97,18 @@ gNullaryToEncodingObjectWithSingleField = genericToEncoding optsObjectWithSingle
96gNullaryParseJSONObjectWithSingleField :: Value -> Parser Nullary
97gNullaryParseJSONObjectWithSingleField :: Value -> Parser Nullary
97gNullaryParseJSONObjectWithSingleField = genericParseJSON optsObjectWithSingleField
98gNullaryParseJSONObjectWithSingleField = genericParseJSON optsObjectWithSingleField
98
99
100+keyOptions :: JSONKeyOptions
101+keyOptions = defaultJSONKeyOptions { keyModifier = ('k' :) }
102+
103+gNullaryToJSONKey :: Nullary -> Either String Text
104+gNullaryToJSONKey x = case genericToJSONKey keyOptions of
105+ ToJSONKeyText p _ -> Right (p x)
106+ _ -> Left "Should be a ToJSONKeyText"
107+
108+gNullaryFromJSONKey :: Text -> Parser Nullary
109+gNullaryFromJSONKey t = case genericFromJSONKey keyOptions of
110+ FromJSONKeyTextParser p -> p t
111+ _ -> fail "Not a TextParser"
99
112
100--------------------------------------------------------------------------------
113--------------------------------------------------------------------------------
101-- SomeType encoders/decoders
114-- SomeType encoders/decoders
tests/UnitTests.hs+46−2
@@ -29,7 +29,13 @@ import Data.Aeson.Internal (JSONPathElement(..), formatError)
29import Data.Aeson.QQ.Simple (aesonQQ)
29import Data.Aeson.QQ.Simple (aesonQQ)
30import Data.Aeson.TH (deriveJSON, deriveToJSON, deriveToJSON1)
30import Data.Aeson.TH (deriveJSON, deriveToJSON, deriveToJSON1)
31import Data.Aeson.Text (encodeToTextBuilder)
31import Data.Aeson.Text (encodeToTextBuilder)
32+import Data.Aeson.Parser
33+ ( json, jsonLast, jsonAccum, jsonNoDup
34+ , json', jsonLast', jsonAccum', jsonNoDup')
35+import Data.Aeson.Types
36+ ( Options(..), Result(Success), ToJSON(..), Value(Array, Bool, Null, Object)
32−import Data.Aeson.Types (Options(..), Result(Success), ToJSON(..), Value(Null, Object), camelTo, camelTo2, defaultOptions, omitNothingFields, parse)
37+ , camelTo, camelTo2, defaultOptions, omitNothingFields, parse)
38+import Data.Attoparsec.ByteString (Parser, parseOnly)
33import Data.Char (toUpper)
39import Data.Char (toUpper)
34import Data.Either.Compat (isLeft, isRight)
40import Data.Either.Compat (isLeft, isRight)
35import Data.Hashable (hash)
41import Data.Hashable (hash)
@@ -47,16 +53,19 @@ import Numeric.Natural (Natural)
47import System.Directory (getDirectoryContents)
53import System.Directory (getDirectoryContents)
48import System.FilePath ((</>), takeExtension, takeFileName)
54import System.FilePath ((</>), takeExtension, takeFileName)
49import Test.Tasty (TestTree, testGroup)
55import Test.Tasty (TestTree, testGroup)
50−import Test.Tasty.HUnit (Assertion, assertBool, assertFailure, assertEqual, testCase)
56+import Test.Tasty.HUnit (Assertion, assertBool, assertFailure, assertEqual, testCase, (@?=))
51import Text.Printf (printf)
57import Text.Printf (printf)
52import UnitTests.NullaryConstructors (nullaryConstructors)
58import UnitTests.NullaryConstructors (nullaryConstructors)
59+import qualified Data.ByteString as S
53import qualified Data.ByteString.Base16.Lazy as LBase16
60import qualified Data.ByteString.Base16.Lazy as LBase16
54import qualified Data.ByteString.Lazy.Char8 as L
61import qualified Data.ByteString.Lazy.Char8 as L
55import qualified Data.HashSet as HashSet
62import qualified Data.HashSet as HashSet
63+import qualified Data.HashMap.Lazy as HashMap
56import qualified Data.Text.Lazy as LT
64import qualified Data.Text.Lazy as LT
57import qualified Data.Text.Lazy.Builder as TLB
65import qualified Data.Text.Lazy.Builder as TLB
58import qualified Data.Text.Lazy.Encoding as LT
66import qualified Data.Text.Lazy.Encoding as LT
59import qualified Data.Text.Lazy.Encoding as TLE
67import qualified Data.Text.Lazy.Encoding as TLE
68+import qualified Data.Vector as Vector
60import qualified ErrorMessages
69import qualified ErrorMessages
61import qualified SerializationFormatSpec
70import qualified SerializationFormatSpec
62
71
@@ -102,6 +111,7 @@ tests = testGroup "unit" [
102 , testGroup "SingleMaybeField" singleMaybeField
111 , testGroup "SingleMaybeField" singleMaybeField
103 , testCase "withEmbeddedJSON" withEmbeddedJSONTest
112 , testCase "withEmbeddedJSON" withEmbeddedJSONTest
104 , testCase "SingleFieldCon" singleFieldCon
113 , testCase "SingleFieldCon" singleFieldCon
114+ , testGroup "Ordering of object keys" keyOrdering
105 , testCase "Ratio with denominator 0" ratioDenominator0
115 , testCase "Ratio with denominator 0" ratioDenominator0
106 , testCase "Big scientific exponent" bigScientificExponent
116 , testCase "Big scientific exponent" bigScientificExponent
107 , testCase "Big integer decoding" bigIntegerDecoding
117 , testCase "Big integer decoding" bigIntegerDecoding
@@ -557,6 +567,40 @@ singleFieldCon :: Assertion
557singleFieldCon =
567singleFieldCon =
558 assertEqual "fromJSON" (Right (SingleFieldCon 0)) (eitherDecode "0")
568 assertEqual "fromJSON" (Right (SingleFieldCon 0)) (eitherDecode "0")
559
569
570+testParser :: (Eq a, Show a)
571+ => String -> Parser a -> S.ByteString -> Either String a -> TestTree
572+testParser name json_ s expected =
573+ testCase name (parseOnly json_ s @?= expected)
574+
575+keyOrdering :: [TestTree]
576+keyOrdering =
577+ [ testParser "json" json
578+ "{\"k\":true,\"k\":false}" $
579+ Right (Object (HashMap.fromList [("k", Bool True)]))
580+ , testParser "jsonLast" jsonLast
581+ "{\"k\":true,\"k\":false}" $
582+ Right (Object (HashMap.fromList [("k", Bool False)]))
583+ , testParser "jsonAccum" jsonAccum
584+ "{\"k\":true,\"k\":false}" $
585+ Right (Object (HashMap.fromList [("k", Array (Vector.fromList [Bool True, Bool False]))]))
586+ , testParser "jsonNoDup" jsonNoDup
587+ "{\"k\":true,\"k\":false}" $
588+ Left "Failed reading: found duplicate key: \"k\""
589+
590+ , testParser "json'" json'
591+ "{\"k\":true,\"k\":false}" $
592+ Right (Object (HashMap.fromList [("k", Bool True)]))
593+ , testParser "jsonLast'" jsonLast'
594+ "{\"k\":true,\"k\":false}" $
595+ Right (Object (HashMap.fromList [("k", Bool False)]))
596+ , testParser "jsonAccum'" jsonAccum'
597+ "{\"k\":true,\"k\":false}" $
598+ Right (Object (HashMap.fromList [("k", Array (Vector.fromList [Bool True, Bool False]))]))
599+ , testParser "jsonNoDup'" jsonNoDup'
600+ "{\"k\":true,\"k\":false}" $
601+ Left "Failed reading: found duplicate key: \"k\""
602+ ]
603+
560ratioDenominator0 :: Assertion
604ratioDenominator0 :: Assertion
561ratioDenominator0 =
605ratioDenominator0 =
562 assertEqual "Ratio with denominator 0"
606 assertEqual "Ratio with denominator 0"
tests/UnitTests/NullaryConstructors.hs+5
@@ -14,6 +14,7 @@ import Data.Aeson (decode, eitherDecode, fromEncoding, Value)
14import Data.Aeson.Internal (IResult (..), iparse)
14import Data.Aeson.Internal (IResult (..), iparse)
15import Data.Aeson.Types (Parser)
15import Data.Aeson.Types (Parser)
16import Data.ByteString.Builder (toLazyByteString)
16import Data.ByteString.Builder (toLazyByteString)
17+import Data.Foldable (for_)
17import Data.Maybe (fromJust)
18import Data.Maybe (fromJust)
18import Encoders
19import Encoders
19import Test.Tasty.HUnit ((@=?), Assertion)
20import Test.Tasty.HUnit ((@=?), Assertion)
@@ -52,6 +53,10 @@ nullaryConstructors =
52 -- Make sure that the old `"contents" : []' is still allowed
53 -- Make sure that the old `"contents" : []' is still allowed
53 , ISuccess C1 @=? parse thNullaryParseJSONTaggedObject (dec "{\"tag\":\"c1\",\"contents\":[]}")
54 , ISuccess C1 @=? parse thNullaryParseJSONTaggedObject (dec "{\"tag\":\"c1\",\"contents\":[]}")
54 , ISuccess C1 @=? parse gNullaryParseJSONTaggedObject (dec "{\"tag\":\"c1\",\"contents\":[]}")
55 , ISuccess C1 @=? parse gNullaryParseJSONTaggedObject (dec "{\"tag\":\"c1\",\"contents\":[]}")
56+
57+ , for_ [("kC1", C1), ("kC2", C2), ("kC3", C3)] $ \(jkey, key) -> do
58+ Right jkey @=? gNullaryToJSONKey key
59+ ISuccess key @=? parse gNullaryFromJSONKey jkey
55 ]
60 ]
56 where
61 where
57 enc = eitherDecode . toLazyByteString . fromEncoding
62 enc = eitherDecode . toLazyByteString . fromEncoding
travis/cabal_macros.hnew file+448
@@ -0,0 +1,448 @@
1+/* DO NOT EDIT: This file is automatically generated by Cabal */
2+
3+/* package aeson-1.4.4.0 */
4+#ifndef VERSION_aeson
5+#define VERSION_aeson "1.4.4.0"
6+#endif /* VERSION_aeson */
7+#ifndef MIN_VERSION_aeson
8+#define MIN_VERSION_aeson(major1,major2,minor) (\
9+ (major1) < 1 || \
10+ (major1) == 1 && (major2) < 4 || \
11+ (major1) == 1 && (major2) == 4 && (minor) <= 4)
12+#endif /* MIN_VERSION_aeson */
13+
14+/* package Diff-0.3.4 */
15+#ifndef VERSION_Diff
16+#define VERSION_Diff "0.3.4"
17+#endif /* VERSION_Diff */
18+#ifndef MIN_VERSION_Diff
19+#define MIN_VERSION_Diff(major1,major2,minor) (\
20+ (major1) < 0 || \
21+ (major1) == 0 && (major2) < 3 || \
22+ (major1) == 0 && (major2) == 3 && (minor) <= 4)
23+#endif /* MIN_VERSION_Diff */
24+
25+/* package QuickCheck-2.13.1 */
26+#ifndef VERSION_QuickCheck
27+#define VERSION_QuickCheck "2.13.1"
28+#endif /* VERSION_QuickCheck */
29+#ifndef MIN_VERSION_QuickCheck
30+#define MIN_VERSION_QuickCheck(major1,major2,minor) (\
31+ (major1) < 2 || \
32+ (major1) == 2 && (major2) < 13 || \
33+ (major1) == 2 && (major2) == 13 && (minor) <= 1)
34+#endif /* MIN_VERSION_QuickCheck */
35+
36+/* package aeson-1.4.4.0 */
37+#ifndef VERSION_aeson
38+#define VERSION_aeson "1.4.4.0"
39+#endif /* VERSION_aeson */
40+#ifndef MIN_VERSION_aeson
41+#define MIN_VERSION_aeson(major1,major2,minor) (\
42+ (major1) < 1 || \
43+ (major1) == 1 && (major2) < 4 || \
44+ (major1) == 1 && (major2) == 4 && (minor) <= 4)
45+#endif /* MIN_VERSION_aeson */
46+
47+/* package attoparsec-0.13.2.2 */
48+#ifndef VERSION_attoparsec
49+#define VERSION_attoparsec "0.13.2.2"
50+#endif /* VERSION_attoparsec */
51+#ifndef MIN_VERSION_attoparsec
52+#define MIN_VERSION_attoparsec(major1,major2,minor) (\
53+ (major1) < 0 || \
54+ (major1) == 0 && (major2) < 13 || \
55+ (major1) == 0 && (major2) == 13 && (minor) <= 2)
56+#endif /* MIN_VERSION_attoparsec */
57+
58+/* package base-4.12.0.0 */
59+#ifndef VERSION_base
60+#define VERSION_base "4.12.0.0"
61+#endif /* VERSION_base */
62+#ifndef MIN_VERSION_base
63+#define MIN_VERSION_base(major1,major2,minor) (\
64+ (major1) < 4 || \
65+ (major1) == 4 && (major2) < 12 || \
66+ (major1) == 4 && (major2) == 12 && (minor) <= 0)
67+#endif /* MIN_VERSION_base */
68+
69+/* package base-compat-0.10.5 */
70+#ifndef VERSION_base_compat
71+#define VERSION_base_compat "0.10.5"
72+#endif /* VERSION_base_compat */
73+#ifndef MIN_VERSION_base_compat
74+#define MIN_VERSION_base_compat(major1,major2,minor) (\
75+ (major1) < 0 || \
76+ (major1) == 0 && (major2) < 10 || \
77+ (major1) == 0 && (major2) == 10 && (minor) <= 5)
78+#endif /* MIN_VERSION_base_compat */
79+
80+/* package base-orphans-0.8.1 */
81+#ifndef VERSION_base_orphans
82+#define VERSION_base_orphans "0.8.1"
83+#endif /* VERSION_base_orphans */
84+#ifndef MIN_VERSION_base_orphans
85+#define MIN_VERSION_base_orphans(major1,major2,minor) (\
86+ (major1) < 0 || \
87+ (major1) == 0 && (major2) < 8 || \
88+ (major1) == 0 && (major2) == 8 && (minor) <= 1)
89+#endif /* MIN_VERSION_base_orphans */
90+
91+/* package base16-bytestring-0.1.1.6 */
92+#ifndef VERSION_base16_bytestring
93+#define VERSION_base16_bytestring "0.1.1.6"
94+#endif /* VERSION_base16_bytestring */
95+#ifndef MIN_VERSION_base16_bytestring
96+#define MIN_VERSION_base16_bytestring(major1,major2,minor) (\
97+ (major1) < 0 || \
98+ (major1) == 0 && (major2) < 1 || \
99+ (major1) == 0 && (major2) == 1 && (minor) <= 1)
100+#endif /* MIN_VERSION_base16_bytestring */
101+
102+/* package bytestring-0.10.8.2 */
103+#ifndef VERSION_bytestring
104+#define VERSION_bytestring "0.10.8.2"
105+#endif /* VERSION_bytestring */
106+#ifndef MIN_VERSION_bytestring
107+#define MIN_VERSION_bytestring(major1,major2,minor) (\
108+ (major1) < 0 || \
109+ (major1) == 0 && (major2) < 10 || \
110+ (major1) == 0 && (major2) == 10 && (minor) <= 8)
111+#endif /* MIN_VERSION_bytestring */
112+
113+/* package containers-0.6.0.1 */
114+#ifndef VERSION_containers
115+#define VERSION_containers "0.6.0.1"
116+#endif /* VERSION_containers */
117+#ifndef MIN_VERSION_containers
118+#define MIN_VERSION_containers(major1,major2,minor) (\
119+ (major1) < 0 || \
120+ (major1) == 0 && (major2) < 6 || \
121+ (major1) == 0 && (major2) == 6 && (minor) <= 0)
122+#endif /* MIN_VERSION_containers */
123+
124+/* package directory-1.3.3.0 */
125+#ifndef VERSION_directory
126+#define VERSION_directory "1.3.3.0"
127+#endif /* VERSION_directory */
128+#ifndef MIN_VERSION_directory
129+#define MIN_VERSION_directory(major1,major2,minor) (\
130+ (major1) < 1 || \
131+ (major1) == 1 && (major2) < 3 || \
132+ (major1) == 1 && (major2) == 3 && (minor) <= 3)
133+#endif /* MIN_VERSION_directory */
134+
135+/* package dlist-0.8.0.6 */
136+#ifndef VERSION_dlist
137+#define VERSION_dlist "0.8.0.6"
138+#endif /* VERSION_dlist */
139+#ifndef MIN_VERSION_dlist
140+#define MIN_VERSION_dlist(major1,major2,minor) (\
141+ (major1) < 0 || \
142+ (major1) == 0 && (major2) < 8 || \
143+ (major1) == 0 && (major2) == 8 && (minor) <= 0)
144+#endif /* MIN_VERSION_dlist */
145+
146+/* package filepath-1.4.2.1 */
147+#ifndef VERSION_filepath
148+#define VERSION_filepath "1.4.2.1"
149+#endif /* VERSION_filepath */
150+#ifndef MIN_VERSION_filepath
151+#define MIN_VERSION_filepath(major1,major2,minor) (\
152+ (major1) < 1 || \
153+ (major1) == 1 && (major2) < 4 || \
154+ (major1) == 1 && (major2) == 4 && (minor) <= 2)
155+#endif /* MIN_VERSION_filepath */
156+
157+/* package generic-deriving-1.12.4 */
158+#ifndef VERSION_generic_deriving
159+#define VERSION_generic_deriving "1.12.4"
160+#endif /* VERSION_generic_deriving */
161+#ifndef MIN_VERSION_generic_deriving
162+#define MIN_VERSION_generic_deriving(major1,major2,minor) (\
163+ (major1) < 1 || \
164+ (major1) == 1 && (major2) < 12 || \
165+ (major1) == 1 && (major2) == 12 && (minor) <= 4)
166+#endif /* MIN_VERSION_generic_deriving */
167+
168+/* package ghc-prim-0.5.3 */
169+#ifndef VERSION_ghc_prim
170+#define VERSION_ghc_prim "0.5.3"
171+#endif /* VERSION_ghc_prim */
172+#ifndef MIN_VERSION_ghc_prim
173+#define MIN_VERSION_ghc_prim(major1,major2,minor) (\
174+ (major1) < 0 || \
175+ (major1) == 0 && (major2) < 5 || \
176+ (major1) == 0 && (major2) == 5 && (minor) <= 3)
177+#endif /* MIN_VERSION_ghc_prim */
178+
179+/* package hashable-1.3.0.0 */
180+#ifndef VERSION_hashable
181+#define VERSION_hashable "1.3.0.0"
182+#endif /* VERSION_hashable */
183+#ifndef MIN_VERSION_hashable
184+#define MIN_VERSION_hashable(major1,major2,minor) (\
185+ (major1) < 1 || \
186+ (major1) == 1 && (major2) < 3 || \
187+ (major1) == 1 && (major2) == 3 && (minor) <= 0)
188+#endif /* MIN_VERSION_hashable */
189+
190+/* package hashable-time-0.2.0.2 */
191+#ifndef VERSION_hashable_time
192+#define VERSION_hashable_time "0.2.0.2"
193+#endif /* VERSION_hashable_time */
194+#ifndef MIN_VERSION_hashable_time
195+#define MIN_VERSION_hashable_time(major1,major2,minor) (\
196+ (major1) < 0 || \
197+ (major1) == 0 && (major2) < 2 || \
198+ (major1) == 0 && (major2) == 2 && (minor) <= 0)
199+#endif /* MIN_VERSION_hashable_time */
200+
201+/* package integer-logarithms-1.0.3 */
202+#ifndef VERSION_integer_logarithms
203+#define VERSION_integer_logarithms "1.0.3"
204+#endif /* VERSION_integer_logarithms */
205+#ifndef MIN_VERSION_integer_logarithms
206+#define MIN_VERSION_integer_logarithms(major1,major2,minor) (\
207+ (major1) < 1 || \
208+ (major1) == 1 && (major2) < 0 || \
209+ (major1) == 1 && (major2) == 0 && (minor) <= 3)
210+#endif /* MIN_VERSION_integer_logarithms */
211+
212+/* package quickcheck-instances-0.3.21 */
213+#ifndef VERSION_quickcheck_instances
214+#define VERSION_quickcheck_instances "0.3.21"
215+#endif /* VERSION_quickcheck_instances */
216+#ifndef MIN_VERSION_quickcheck_instances
217+#define MIN_VERSION_quickcheck_instances(major1,major2,minor) (\
218+ (major1) < 0 || \
219+ (major1) == 0 && (major2) < 3 || \
220+ (major1) == 0 && (major2) == 3 && (minor) <= 21)
221+#endif /* MIN_VERSION_quickcheck_instances */
222+
223+/* package scientific-0.3.6.2 */
224+#ifndef VERSION_scientific
225+#define VERSION_scientific "0.3.6.2"
226+#endif /* VERSION_scientific */
227+#ifndef MIN_VERSION_scientific
228+#define MIN_VERSION_scientific(major1,major2,minor) (\
229+ (major1) < 0 || \
230+ (major1) == 0 && (major2) < 3 || \
231+ (major1) == 0 && (major2) == 3 && (minor) <= 6)
232+#endif /* MIN_VERSION_scientific */
233+
234+/* package tagged-0.8.6 */
235+#ifndef VERSION_tagged
236+#define VERSION_tagged "0.8.6"
237+#endif /* VERSION_tagged */
238+#ifndef MIN_VERSION_tagged
239+#define MIN_VERSION_tagged(major1,major2,minor) (\
240+ (major1) < 0 || \
241+ (major1) == 0 && (major2) < 8 || \
242+ (major1) == 0 && (major2) == 8 && (minor) <= 6)
243+#endif /* MIN_VERSION_tagged */
244+
245+/* package tasty-1.2.3 */
246+#ifndef VERSION_tasty
247+#define VERSION_tasty "1.2.3"
248+#endif /* VERSION_tasty */
249+#ifndef MIN_VERSION_tasty
250+#define MIN_VERSION_tasty(major1,major2,minor) (\
251+ (major1) < 1 || \
252+ (major1) == 1 && (major2) < 2 || \
253+ (major1) == 1 && (major2) == 2 && (minor) <= 3)
254+#endif /* MIN_VERSION_tasty */
255+
256+/* package tasty-golden-2.3.2 */
257+#ifndef VERSION_tasty_golden
258+#define VERSION_tasty_golden "2.3.2"
259+#endif /* VERSION_tasty_golden */
260+#ifndef MIN_VERSION_tasty_golden
261+#define MIN_VERSION_tasty_golden(major1,major2,minor) (\
262+ (major1) < 2 || \
263+ (major1) == 2 && (major2) < 3 || \
264+ (major1) == 2 && (major2) == 3 && (minor) <= 2)
265+#endif /* MIN_VERSION_tasty_golden */
266+
267+/* package tasty-hunit-0.10.0.2 */
268+#ifndef VERSION_tasty_hunit
269+#define VERSION_tasty_hunit "0.10.0.2"
270+#endif /* VERSION_tasty_hunit */
271+#ifndef MIN_VERSION_tasty_hunit
272+#define MIN_VERSION_tasty_hunit(major1,major2,minor) (\
273+ (major1) < 0 || \
274+ (major1) == 0 && (major2) < 10 || \
275+ (major1) == 0 && (major2) == 10 && (minor) <= 0)
276+#endif /* MIN_VERSION_tasty_hunit */
277+
278+/* package tasty-quickcheck-0.10.1 */
279+#ifndef VERSION_tasty_quickcheck
280+#define VERSION_tasty_quickcheck "0.10.1"
281+#endif /* VERSION_tasty_quickcheck */
282+#ifndef MIN_VERSION_tasty_quickcheck
283+#define MIN_VERSION_tasty_quickcheck(major1,major2,minor) (\
284+ (major1) < 0 || \
285+ (major1) == 0 && (major2) < 10 || \
286+ (major1) == 0 && (major2) == 10 && (minor) <= 1)
287+#endif /* MIN_VERSION_tasty_quickcheck */
288+
289+/* package template-haskell-2.14.0.0 */
290+#ifndef VERSION_template_haskell
291+#define VERSION_template_haskell "2.14.0.0"
292+#endif /* VERSION_template_haskell */
293+#ifndef MIN_VERSION_template_haskell
294+#define MIN_VERSION_template_haskell(major1,major2,minor) (\
295+ (major1) < 2 || \
296+ (major1) == 2 && (major2) < 14 || \
297+ (major1) == 2 && (major2) == 14 && (minor) <= 0)
298+#endif /* MIN_VERSION_template_haskell */
299+
300+/* package text-1.2.3.1 */
301+#ifndef VERSION_text
302+#define VERSION_text "1.2.3.1"
303+#endif /* VERSION_text */
304+#ifndef MIN_VERSION_text
305+#define MIN_VERSION_text(major1,major2,minor) (\
306+ (major1) < 1 || \
307+ (major1) == 1 && (major2) < 2 || \
308+ (major1) == 1 && (major2) == 2 && (minor) <= 3)
309+#endif /* MIN_VERSION_text */
310+
311+/* package time-1.8.0.2 */
312+#ifndef VERSION_time
313+#define VERSION_time "1.8.0.2"
314+#endif /* VERSION_time */
315+#ifndef MIN_VERSION_time
316+#define MIN_VERSION_time(major1,major2,minor) (\
317+ (major1) < 1 || \
318+ (major1) == 1 && (major2) < 8 || \
319+ (major1) == 1 && (major2) == 8 && (minor) <= 0)
320+#endif /* MIN_VERSION_time */
321+
322+/* package time-compat-1.9.2.2 */
323+#ifndef VERSION_time_compat
324+#define VERSION_time_compat "1.9.2.2"
325+#endif /* VERSION_time_compat */
326+#ifndef MIN_VERSION_time_compat
327+#define MIN_VERSION_time_compat(major1,major2,minor) (\
328+ (major1) < 1 || \
329+ (major1) == 1 && (major2) < 9 || \
330+ (major1) == 1 && (major2) == 9 && (minor) <= 2)
331+#endif /* MIN_VERSION_time_compat */
332+
333+/* package unordered-containers-0.2.10.0 */
334+#ifndef VERSION_unordered_containers
335+#define VERSION_unordered_containers "0.2.10.0"
336+#endif /* VERSION_unordered_containers */
337+#ifndef MIN_VERSION_unordered_containers
338+#define MIN_VERSION_unordered_containers(major1,major2,minor) (\
339+ (major1) < 0 || \
340+ (major1) == 0 && (major2) < 2 || \
341+ (major1) == 0 && (major2) == 2 && (minor) <= 10)
342+#endif /* MIN_VERSION_unordered_containers */
343+
344+/* package uuid-types-1.0.3 */
345+#ifndef VERSION_uuid_types
346+#define VERSION_uuid_types "1.0.3"
347+#endif /* VERSION_uuid_types */
348+#ifndef MIN_VERSION_uuid_types
349+#define MIN_VERSION_uuid_types(major1,major2,minor) (\
350+ (major1) < 1 || \
351+ (major1) == 1 && (major2) < 0 || \
352+ (major1) == 1 && (major2) == 0 && (minor) <= 3)
353+#endif /* MIN_VERSION_uuid_types */
354+
355+/* package vector-0.12.0.3 */
356+#ifndef VERSION_vector
357+#define VERSION_vector "0.12.0.3"
358+#endif /* VERSION_vector */
359+#ifndef MIN_VERSION_vector
360+#define MIN_VERSION_vector(major1,major2,minor) (\
361+ (major1) < 0 || \
362+ (major1) == 0 && (major2) < 12 || \
363+ (major1) == 0 && (major2) == 12 && (minor) <= 0)
364+#endif /* MIN_VERSION_vector */
365+
366+/* tool gcc-4.2.1 */
367+#ifndef TOOL_VERSION_gcc
368+#define TOOL_VERSION_gcc "4.2.1"
369+#endif /* TOOL_VERSION_gcc */
370+#ifndef MIN_TOOL_VERSION_gcc
371+#define MIN_TOOL_VERSION_gcc(major1,major2,minor) (\
372+ (major1) < 4 || \
373+ (major1) == 4 && (major2) < 2 || \
374+ (major1) == 4 && (major2) == 2 && (minor) <= 1)
375+#endif /* MIN_TOOL_VERSION_gcc */
376+
377+/* tool ghc-8.6.5 */
378+#ifndef TOOL_VERSION_ghc
379+#define TOOL_VERSION_ghc "8.6.5"
380+#endif /* TOOL_VERSION_ghc */
381+#ifndef MIN_TOOL_VERSION_ghc
382+#define MIN_TOOL_VERSION_ghc(major1,major2,minor) (\
383+ (major1) < 8 || \
384+ (major1) == 8 && (major2) < 6 || \
385+ (major1) == 8 && (major2) == 6 && (minor) <= 5)
386+#endif /* MIN_TOOL_VERSION_ghc */
387+
388+/* tool ghc-pkg-8.6.5 */
389+#ifndef TOOL_VERSION_ghc_pkg
390+#define TOOL_VERSION_ghc_pkg "8.6.5"
391+#endif /* TOOL_VERSION_ghc_pkg */
392+#ifndef MIN_TOOL_VERSION_ghc_pkg
393+#define MIN_TOOL_VERSION_ghc_pkg(major1,major2,minor) (\
394+ (major1) < 8 || \
395+ (major1) == 8 && (major2) < 6 || \
396+ (major1) == 8 && (major2) == 6 && (minor) <= 5)
397+#endif /* MIN_TOOL_VERSION_ghc_pkg */
398+
399+/* tool haddock-2.22.0 */
400+#ifndef TOOL_VERSION_haddock
401+#define TOOL_VERSION_haddock "2.22.0"
402+#endif /* TOOL_VERSION_haddock */
403+#ifndef MIN_TOOL_VERSION_haddock
404+#define MIN_TOOL_VERSION_haddock(major1,major2,minor) (\
405+ (major1) < 2 || \
406+ (major1) == 2 && (major2) < 22 || \
407+ (major1) == 2 && (major2) == 22 && (minor) <= 0)
408+#endif /* MIN_TOOL_VERSION_haddock */
409+
410+/* tool hpc-0.67 */
411+#ifndef TOOL_VERSION_hpc
412+#define TOOL_VERSION_hpc "0.67"
413+#endif /* TOOL_VERSION_hpc */
414+#ifndef MIN_TOOL_VERSION_hpc
415+#define MIN_TOOL_VERSION_hpc(major1,major2,minor) (\
416+ (major1) < 0 || \
417+ (major1) == 0 && (major2) < 67 || \
418+ (major1) == 0 && (major2) == 67 && (minor) <= 0)
419+#endif /* MIN_TOOL_VERSION_hpc */
420+
421+/* tool hsc2hs-0.68.5 */
422+#ifndef TOOL_VERSION_hsc2hs
423+#define TOOL_VERSION_hsc2hs "0.68.5"
424+#endif /* TOOL_VERSION_hsc2hs */
425+#ifndef MIN_TOOL_VERSION_hsc2hs
426+#define MIN_TOOL_VERSION_hsc2hs(major1,major2,minor) (\
427+ (major1) < 0 || \
428+ (major1) == 0 && (major2) < 68 || \
429+ (major1) == 0 && (major2) == 68 && (minor) <= 5)
430+#endif /* MIN_TOOL_VERSION_hsc2hs */
431+
432+/* tool runghc-8.6.5 */
433+#ifndef TOOL_VERSION_runghc
434+#define TOOL_VERSION_runghc "8.6.5"
435+#endif /* TOOL_VERSION_runghc */
436+#ifndef MIN_TOOL_VERSION_runghc
437+#define MIN_TOOL_VERSION_runghc(major1,major2,minor) (\
438+ (major1) < 8 || \
439+ (major1) == 8 && (major2) < 6 || \
440+ (major1) == 8 && (major2) == 6 && (minor) <= 5)
441+#endif /* MIN_TOOL_VERSION_runghc */
442+
443+#ifndef CURRENT_COMPONENT_ID
444+#define CURRENT_COMPONENT_ID "aeson-1.4.4.0-inplace-tests"
445+#endif /* CURRENT_COMPONENT_ID */
446+#ifndef CURRENT_PACKAGE_VERSION
447+#define CURRENT_PACKAGE_VERSION "1.4.4.0"
448+#endif /* CURRENT_PACKAGE_VERSION */
travis/install.sh+11
@@ -7,6 +7,11 @@ echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo
7stack --version
7stack --version
8
8
9case $BUILD in
9case $BUILD in
10+ hlint)
11+ echo "Downloading hlint"
12+ curl -sSL https://raw.github.com/ndmitchell/hlint/master/misc/run.sh > hlint.sh
13+ chmod +x hlint.sh
14+ ;;
10 stack)
15 stack)
11 stack --no-terminal --skip-ghc-check setup
16 stack --no-terminal --skip-ghc-check setup
12 stack --no-terminal --skip-ghc-check test --only-snapshot
17 stack --no-terminal --skip-ghc-check test --only-snapshot
@@ -44,4 +49,10 @@ case $BUILD in
44 cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;
49 cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;
45 fi
50 fi
46 ;;
51 ;;
52+ cabal2)
53+ cabal v2-update -v
54+ sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
55+
56+ cabal v2-build --only-dependencies --enable-tests --enable-benchmarks --dry
57+ ;;
47esac
58esac
travis/script.sh+4−2
@@ -19,9 +19,11 @@ case $BUILD in
19 SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
19 SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
20 (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
20 (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
21 ;;
21 ;;
22+ cabal2)
23+ cabal v2-build --enable-tests --enable-benchmarks
24+ cabal v2-test --enable-tests --enable-benchmarks
25+ ;;
22 hlint)
26 hlint)
23− stack build --fast aeson --stack-yaml stack-nightly.yaml --system-ghc --no-terminal
24− stack install hlint --stack-yaml stack-nightly.yaml --system-ghc --no-terminal
25 make lint
27 make lint
26 ;;
28 ;;
27esac
29esac