git.iko.soy/typeable/http-api-data
on master help sign in
Add Semigroup.Min/Max/First/Last and Tagged instances

- Explicit import lists - use `coerce` (I thought about StandaloneDeriving, but it would be nicer with `DerivingStrategies`)

commit6454ed070c9dec034b1c03a6ab8d0bb75b3fce91 authorOleg Grenrus <oleg.grenrus@iki.fi> dateTue 13 Nov 2018, 12:38 (8 years ago) parent3e87ab0
6 files changed+176−106
.travis.yml+6−7 CHANGELOG.md+7 http-api-data.cabal+6−3 src/Web/Internal/FormUrlEncoded.hs+35−21 src/Web/Internal/HttpApiData.hs+92−49 test/Web/Internal/HttpApiDataSpec.hs+30−26
.travis.yml+6−7
@@ -32,12 +32,12 @@ before_cache:
3232
3333matrix:
3434 include:
35− - compiler: "ghc-8.6.1"
35+ - compiler: "ghc-8.6.2"
3636 # env: TEST=--disable-tests BENCH=--disable-benchmarks
37− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.1], sources: [hvr-ghc]}}
38− - compiler: "ghc-8.4.3"
37+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.2], sources: [hvr-ghc]}}
38+ - compiler: "ghc-8.4.4"
3939 # env: TEST=--disable-tests BENCH=--disable-benchmarks
40− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.3], sources: [hvr-ghc]}}
40+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}
4141 - compiler: "ghc-8.2.2"
4242 # env: TEST=--disable-tests BENCH=--disable-benchmarks
4343 addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.2.2], sources: [hvr-ghc]}}
@@ -93,8 +93,8 @@ install:
9393# any command which exits with a non-zero exit code causes the build to fail.
9494script:
9595 # test that source-distributions can be generated
96− - (cd "." && cabal sdist)
97− - mv "."/dist/http-api-data-*.tar.gz ${DISTDIR}/
96+ - cabal new-sdist all
97+ - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
9898 - cd ${DISTDIR} || false
9999 - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
100100 - "printf 'packages: http-api-data-*/*.cabal\\n' > cabal.project"
@@ -113,7 +113,6 @@ script:
113113 - (cd http-api-data-* && cabal check)
114114
115115 # haddock
116− - rm -rf ./dist-newstyle
117116 - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi
118117
119118 # Build without installed constraints for packages in global-db
CHANGELOG.md+7
@@ -1,3 +1,10 @@
1+0.4
2+---
3+
4+* `NominalDiffTime` instances preserve precision (roundtrip)
5+* Add `Semigroup.Min`, `Max`, `First`, `Last` instances
6+* Add `Tagged b a` instances
7+
180.3.10
29---
310
http-api-data.cabal+6−3
@@ -1,6 +1,6 @@
11cabal-version: >= 1.10
22name: http-api-data
3−version: 0.3.10
3+version: 0.4
44
55synopsis: Converting to/from HTTP API data like URL pieces, headers and query parameters.
66category: Web
@@ -22,13 +22,14 @@ extra-source-files:
2222 test/*.hs
2323 CHANGELOG.md
2424 README.md
25+
2526tested-with:
2627 GHC==7.8.4,
2728 GHC==7.10.3,
2829 GHC==8.0.2,
2930 GHC==8.2.2,
30− GHC==8.4.3,
31− GHC==8.6.1
31+ GHC==8.4.4,
32+ GHC==8.6.2
3233
3334custom-setup
3435 setup-depends:
@@ -60,6 +61,7 @@ library
6061 , cookie >= 0.4.3 && < 0.4.5
6162 , hashable >= 1.2.7.0 && < 1.3
6263 , http-types >= 0.12.2 && < 0.13
64+ , tagged >= 0.8.5 && < 0.9
6365 , time-locale-compat >= 0.1.1.5 && < 0.2
6466 , unordered-containers >= 0.2.9.0 && < 0.3
6567 , uuid-types >= 1.0.3 && <1.1
@@ -98,6 +100,7 @@ test-suite spec
98100 -- inherited depndencies
99101 build-depends:
100102 base
103+ , base-compat
101104 , bytestring
102105 , cookie
103106 , http-api-data
src/Web/Internal/FormUrlEncoded.hs+35−21
@@ -17,7 +17,7 @@
1717#include "overlapping-compat.h"
1818module Web.Internal.FormUrlEncoded where
1919
20−import Prelude ()
20+import Prelude ()
2121import Prelude.Compat
2222
2323import Control.Arrow ((***))
@@ -25,38 +25,38 @@ import Control.Monad ((<=<))
2525import Data.ByteString.Builder (shortByteString, toLazyByteString)
2626import qualified Data.ByteString.Lazy as BSL
2727import qualified Data.ByteString.Lazy.Char8 as BSL8
28+import Data.Coerce (coerce)
2829import qualified Data.Foldable as F
2930import Data.Hashable (Hashable)
3031import Data.HashMap.Strict (HashMap)
3132import qualified Data.HashMap.Strict as HashMap
32−import Data.Int
33+import Data.Int (Int16, Int32, Int64, Int8)
3334import Data.IntMap (IntMap)
3435import qualified Data.IntMap as IntMap
3536import Data.List (intersperse, sortBy)
3637import Data.Map (Map)
3738import qualified Data.Map as Map
38−import Data.Monoid
39+import Data.Monoid (All (..), Any (..), Dual (..),
40+ Product (..), Sum (..))
3941import Data.Ord (comparing)
42+import Data.Proxy (Proxy (..))
43+import Data.Semigroup (Semigroup (..))
4044import qualified Data.Semigroup as Semi
41−
45+import Data.Tagged (Tagged (..))
4246import Data.Text (Text)
4347import qualified Data.Text as Text
44−import Data.Text.Encoding as Text
48+import qualified Data.Text.Encoding as Text
4549import Data.Text.Encoding.Error (lenientDecode)
4650import qualified Data.Text.Lazy as Lazy
47−
48−import Data.Proxy
49−import Data.Time
50−import Data.Word
51−
52−import Data.Void
53−import Numeric.Natural
54−
51+import Data.Time (Day, LocalTime, NominalDiffTime,
52+ UTCTime, ZonedTime)
53+import Data.Void (Void)
54+import Data.Word (Word16, Word32, Word64, Word8)
5555import GHC.Exts (Constraint, IsList (..))
5656import GHC.Generics
5757import GHC.TypeLits
5858import Network.HTTP.Types.URI (urlDecode, urlEncodeBuilder)
59−
59+import Numeric.Natural (Natural)
6060import Web.Internal.HttpApiData
6161
6262-- $setup
@@ -119,9 +119,16 @@ instance ToFormKey Lazy.Text where toFormKey = toQueryParam
119119instance ToFormKey All where toFormKey = toQueryParam
120120instance ToFormKey Any where toFormKey = toQueryParam
121121
122−instance ToFormKey a => ToFormKey (Dual a) where toFormKey = toFormKey . getDual
123−instance ToFormKey a => ToFormKey (Sum a) where toFormKey = toFormKey . getSum
124−instance ToFormKey a => ToFormKey (Product a) where toFormKey = toFormKey . getProduct
122+instance ToFormKey a => ToFormKey (Dual a) where toFormKey = coerce (toFormKey :: a -> Text)
123+instance ToFormKey a => ToFormKey (Sum a) where toFormKey = coerce (toFormKey :: a -> Text)
124+instance ToFormKey a => ToFormKey (Product a) where toFormKey = coerce (toFormKey :: a -> Text)
125+
126+instance ToFormKey a => ToFormKey (Semi.Min a) where toFormKey = coerce (toFormKey :: a -> Text)
127+instance ToFormKey a => ToFormKey (Semi.Max a) where toFormKey = coerce (toFormKey :: a -> Text)
128+instance ToFormKey a => ToFormKey (Semi.First a) where toFormKey = coerce (toFormKey :: a -> Text)
129+instance ToFormKey a => ToFormKey (Semi.Last a) where toFormKey = coerce (toFormKey :: a -> Text)
130+
131+instance ToFormKey a => ToFormKey (Tagged b a) where toFormKey = coerce (toFormKey :: a -> Text)
125132
126133instance ToFormKey Void where toFormKey = toQueryParam
127134instance ToFormKey Natural where toFormKey = toQueryParam
@@ -164,9 +171,16 @@ instance FromFormKey Lazy.Text where parseFormKey = parseQueryParam
164171instance FromFormKey All where parseFormKey = parseQueryParam
165172instance FromFormKey Any where parseFormKey = parseQueryParam
166173
167−instance FromFormKey a => FromFormKey (Dual a) where parseFormKey = fmap Dual . parseFormKey
168−instance FromFormKey a => FromFormKey (Sum a) where parseFormKey = fmap Sum . parseFormKey
169−instance FromFormKey a => FromFormKey (Product a) where parseFormKey = fmap Product . parseFormKey
174+instance FromFormKey a => FromFormKey (Dual a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
175+instance FromFormKey a => FromFormKey (Sum a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
176+instance FromFormKey a => FromFormKey (Product a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
177+
178+instance FromFormKey a => FromFormKey (Semi.Min a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
179+instance FromFormKey a => FromFormKey (Semi.Max a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
180+instance FromFormKey a => FromFormKey (Semi.First a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
181+instance FromFormKey a => FromFormKey (Semi.Last a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
182+
183+instance FromFormKey a => FromFormKey (Tagged b a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
170184
171185instance FromFormKey Void where parseFormKey = parseQueryParam
172186instance FromFormKey Natural where parseFormKey = parseQueryParam
@@ -175,7 +189,7 @@ instance FromFormKey Natural where parseFormKey = parseQueryParam
175189--
176190-- 'Form' can be URL-encoded with 'urlEncodeForm' and URL-decoded with 'urlDecodeForm'.
177191newtype Form = Form { unForm :: HashMap Text [Text] }
178− deriving (Eq, Read, Generic, Semi.Semigroup, Monoid)
192+ deriving (Eq, Read, Generic, Semigroup, Monoid)
179193
180194instance Show Form where
181195 showsPrec d form = showParen (d > 10) $
src/Web/Internal/HttpApiData.hs+92−49
@@ -13,21 +13,27 @@
1313-- such as URL pieces, headers and query parameters.
1414module Web.Internal.HttpApiData where
1515
16−import Prelude ()
16+import Prelude ()
1717import Prelude.Compat
1818
1919import Control.Arrow (left, (&&&))
2020import Control.Monad ((<=<))
21−
21+import qualified Data.Attoparsec.Text as Atto
22+import qualified Data.Attoparsec.Time as Atto
2223import Data.ByteString (ByteString)
2324import qualified Data.ByteString as BS
25+import qualified Data.ByteString.Builder as BS
2426import qualified Data.ByteString.Lazy as LBS
25−import Data.Monoid
26−
27+import Data.Coerce (coerce)
28+import Data.Data (Data)
2729import qualified Data.Fixed as F
28−import Data.Int
29−import Data.Word
30−
30+import Data.Int (Int16, Int32, Int64, Int8)
31+import Data.Monoid (All (..), Any (..), Dual (..),
32+ First (..), Last (..),
33+ Product (..), Sum (..))
34+import Data.Semigroup (Semigroup (..))
35+import qualified Data.Semigroup as Semi
36+import Data.Tagged (Tagged (..))
3137import Data.Text (Text)
3238import qualified Data.Text as T
3339import Data.Text.Encoding (decodeUtf8', decodeUtf8With,
@@ -36,43 +42,41 @@ import Data.Text.Encoding.Error (lenientDecode)
3642import qualified Data.Text.Lazy as L
3743import Data.Text.Read (Reader, decimal, rational,
3844 signed)
39−
40−import Data.Time
41−import Data.Time.Locale.Compat
45+import Data.Time (Day, FormatTime, LocalTime,
46+ NominalDiffTime, TimeOfDay,
47+ UTCTime, ZonedTime, formatTime)
48+import Data.Time.Locale.Compat (defaultTimeLocale,
49+ iso8601DateFormat)
50+import Data.Typeable (Typeable)
51+import qualified Data.UUID.Types as UUID
52+import Data.Version (Version, parseVersion,
53+ showVersion)
54+import Data.Void (Void, absurd)
55+import Data.Word (Word16, Word32, Word64, Word8)
56+import qualified Network.HTTP.Types as H
57+import Numeric.Natural (Natural)
58+import Text.ParserCombinators.ReadP (readP_to_S)
59+import Text.Read (readMaybe)
60+import Web.Cookie (SetCookie, parseSetCookie,
61+ renderSetCookie)
4262
4363#if MIN_VERSION_time(1,9,1)
44−import Data.Time (nominalDiffTimeToSeconds, secondsToNominalDiffTime)
64+import Data.Time (nominalDiffTimeToSeconds,
65+ secondsToNominalDiffTime)
4566#endif
4667
47−import Data.Version
48−
49−import Data.Void
50−import Numeric.Natural
51−
52−import Text.ParserCombinators.ReadP (readP_to_S)
53−import Text.Read (readMaybe)
54−
5568#if USE_TEXT_SHOW
5669import TextShow (TextShow, showt)
5770#endif
5871
59−import qualified Data.UUID.Types as UUID
6072
61−import qualified Data.ByteString.Builder as BS
62−import Data.Data (Data)
63−import Data.Typeable (Typeable)
64−import qualified Network.HTTP.Types as H
65−
66−import qualified Data.Attoparsec.Text as Atto
67−import qualified Data.Attoparsec.Time as Atto
68−
69−import Web.Cookie (SetCookie, parseSetCookie,
70− renderSetCookie)
7173
7274
7375-- $setup
7476-- >>> data BasicAuthToken = BasicAuthToken Text deriving (Show)
7577-- >>> instance FromHttpApiData BasicAuthToken where parseHeader h = BasicAuthToken <$> parseHeaderWithPrefix "Basic " h; parseQueryParam p = BasicAuthToken <$> parseQueryParam p
78+-- >>> import Data.Time
79+-- >>> import Data.Version
7680
7781-- | Convert value to HTTP API data.
7882--
@@ -519,28 +523,49 @@ instance ToHttpApiData String where toUrlPiece = T.pack
519523instance ToHttpApiData Text where toUrlPiece = id
520524instance ToHttpApiData L.Text where toUrlPiece = L.toStrict
521525
522−instance ToHttpApiData All where toUrlPiece = toUrlPiece . getAll; toEncodedUrlPiece = toEncodedUrlPiece . getAll
523−instance ToHttpApiData Any where toUrlPiece = toUrlPiece . getAny; toEncodedUrlPiece = toEncodedUrlPiece . getAny
526+instance ToHttpApiData All where
527+ toUrlPiece = coerce (toUrlPiece :: Bool -> Text)
528+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: Bool -> BS.Builder)
529+
530+instance ToHttpApiData Any where
531+ toUrlPiece = coerce (toUrlPiece :: Bool -> Text)
532+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: Bool -> BS.Builder)
524533
525534instance ToHttpApiData a => ToHttpApiData (Dual a) where
526− toUrlPiece = toUrlPiece . getDual
527− toEncodedUrlPiece = toEncodedUrlPiece . getDual
535+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
536+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
528537
529538instance ToHttpApiData a => ToHttpApiData (Sum a) where
530− toUrlPiece = toUrlPiece . getSum
531− toEncodedUrlPiece = toEncodedUrlPiece . getSum
539+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
540+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
532541
533542instance ToHttpApiData a => ToHttpApiData (Product a) where
534− toUrlPiece = toUrlPiece . getProduct
535− toEncodedUrlPiece = toEncodedUrlPiece . getProduct
543+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
544+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
536545
537546instance ToHttpApiData a => ToHttpApiData (First a) where
538− toUrlPiece = toUrlPiece . getFirst
539− toEncodedUrlPiece = toEncodedUrlPiece . getFirst
547+ toUrlPiece = coerce (toUrlPiece :: Maybe a -> Text)
548+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: Maybe a -> BS.Builder)
540549
541550instance ToHttpApiData a => ToHttpApiData (Last a) where
542− toUrlPiece = toUrlPiece . getLast
543− toEncodedUrlPiece = toEncodedUrlPiece . getLast
551+ toUrlPiece = coerce (toUrlPiece :: Maybe a -> Text)
552+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: Maybe a -> BS.Builder)
553+
554+instance ToHttpApiData a => ToHttpApiData (Semi.Min a) where
555+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
556+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
557+
558+instance ToHttpApiData a => ToHttpApiData (Semi.Max a) where
559+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
560+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
561+
562+instance ToHttpApiData a => ToHttpApiData (Semi.First a) where
563+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
564+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
565+
566+instance ToHttpApiData a => ToHttpApiData (Semi.Last a) where
567+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
568+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
544569
545570-- |
546571-- >>> toUrlPiece (Just "Hello")
@@ -572,6 +597,12 @@ instance ToHttpApiData SetCookie where
572597 toHeader = LBS.toStrict . BS.toLazyByteString . renderSetCookie
573598 -- toEncodedUrlPiece = renderSetCookie -- doesn't do things.
574599
600+instance ToHttpApiData a => ToHttpApiData (Tagged b a) where
601+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
602+ toHeader = coerce (toHeader :: a -> ByteString)
603+ toQueryParam = coerce (toQueryParam :: a -> Text)
604+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
605+
575606-- |
576607-- >>> parseUrlPiece "_" :: Either Text ()
577608-- Right ()
@@ -657,14 +688,19 @@ instance FromHttpApiData UTCTime where parseUrlPiece = runAtto Atto.utcTime
657688
658689instance FromHttpApiData NominalDiffTime where parseUrlPiece = fmap secsToNominalDiffTime . parseUrlPiece
659690
660−instance FromHttpApiData All where parseUrlPiece = fmap All . parseUrlPiece
661−instance FromHttpApiData Any where parseUrlPiece = fmap Any . parseUrlPiece
691+instance FromHttpApiData All where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
692+instance FromHttpApiData Any where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
693+
694+instance FromHttpApiData a => FromHttpApiData (Dual a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
695+instance FromHttpApiData a => FromHttpApiData (Sum a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
696+instance FromHttpApiData a => FromHttpApiData (Product a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
697+instance FromHttpApiData a => FromHttpApiData (First a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text (Maybe a))
698+instance FromHttpApiData a => FromHttpApiData (Last a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text (Maybe a))
662699
663−instance FromHttpApiData a => FromHttpApiData (Dual a) where parseUrlPiece = fmap Dual . parseUrlPiece
664−instance FromHttpApiData a => FromHttpApiData (Sum a) where parseUrlPiece = fmap Sum . parseUrlPiece
665−instance FromHttpApiData a => FromHttpApiData (Product a) where parseUrlPiece = fmap Product . parseUrlPiece
666−instance FromHttpApiData a => FromHttpApiData (First a) where parseUrlPiece = fmap First . parseUrlPiece
667−instance FromHttpApiData a => FromHttpApiData (Last a) where parseUrlPiece = fmap Last . parseUrlPiece
700+instance FromHttpApiData a => FromHttpApiData (Semi.Min a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
701+instance FromHttpApiData a => FromHttpApiData (Semi.Max a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
702+instance FromHttpApiData a => FromHttpApiData (Semi.First a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
703+instance FromHttpApiData a => FromHttpApiData (Semi.Last a) where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
668704
669705-- |
670706-- >>> parseUrlPiece "Just 123" :: Either Text (Maybe Int)
@@ -715,6 +751,11 @@ instance FromHttpApiData SetCookie where
715751 parseUrlPiece = parseHeader . encodeUtf8
716752 parseHeader = Right . parseSetCookie
717753
754+instance FromHttpApiData a => FromHttpApiData (Tagged b a) where
755+ parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
756+ parseHeader = coerce (parseHeader :: ByteString -> Either Text a)
757+ parseQueryParam = coerce (parseQueryParam :: Text -> Either Text a)
758+
718759-------------------------------------------------------------------------------
719760-- Attoparsec helpers
720761-------------------------------------------------------------------------------
@@ -723,3 +764,5 @@ runAtto :: Atto.Parser a -> Text -> Either Text a
723764runAtto p t = case Atto.parseOnly (p <* Atto.endOfInput) t of
724765 Left err -> Left (T.pack err)
725766 Right x -> Right x
767+
768+
test/Web/Internal/HttpApiDataSpec.hs+30−26
@@ -1,32 +1,36 @@
11{-# LANGUAGE ScopedTypeVariables #-}
22module Web.Internal.HttpApiDataSpec (spec) where
33
4−import Control.Applicative
5−import qualified Data.Fixed as F
6−import Data.Int
7−import Data.Char
8−import Data.Word
9−import Data.Time
10−import qualified Data.Text as T
11−import qualified Data.Text.Encoding as TE
12−import qualified Data.Text.Lazy as L
13−import qualified Data.ByteString as BS
14−import Data.ByteString.Builder (toLazyByteString)
15−import Data.Version
16−import qualified Data.UUID.Types as UUID
17−import Web.Cookie (SetCookie, defaultSetCookie, setCookieName, setCookieValue)
18−
19−import Data.Proxy
20−
21−import Numeric.Natural
22−
23−import Test.Hspec
24−import Test.Hspec.QuickCheck(prop)
25−import Test.QuickCheck
26−
27−import Web.Internal.HttpApiData
28−
29−import Web.Internal.TestInstances
4+
5+import Prelude ()
6+import Prelude.Compat
7+
8+import qualified Data.ByteString as BS
9+import Data.ByteString.Builder (toLazyByteString)
10+import Data.Char
11+import qualified Data.Fixed as F
12+import Data.Int
13+import qualified Data.Text as T
14+import qualified Data.Text.Encoding as TE
15+import qualified Data.Text.Lazy as L
16+import Data.Time
17+import qualified Data.UUID.Types as UUID
18+import Data.Version
19+import Data.Word
20+import Web.Cookie (SetCookie, defaultSetCookie,
21+ setCookieName, setCookieValue)
22+
23+import Data.Proxy
24+
25+import Numeric.Natural
26+
27+import Test.Hspec
28+import Test.Hspec.QuickCheck (prop)
29+import Test.QuickCheck
30+
31+import Web.Internal.HttpApiData
32+
33+import Web.Internal.TestInstances
3034
3135(<=>) :: forall a b. (Show a, Show b, Eq a) => (a -> b) -> (b -> Either T.Text a) -> a -> Property
3236(f <=> g) x = counterexample