git.iko.soy/typeable/http-api-data
on master help sign in
.ghcideleted−1
since splitsnapshots
unifiedsplit
@@ -1 +0,0 @@
1−:set -itest -isrc -optP-include -optP .stack-work/dist/x86_64-osx/Cabal-1.24.0.0/build/autogen/cabal_macros.h -optP-I -optPinclude
.github/workflows/haskell-ci.yml+125−41
@@ -8,9 +8,9 @@
8#
8#
9# For more information, see https://github.com/haskell-CI/haskell-ci
9# For more information, see https://github.com/haskell-CI/haskell-ci
10#
10#
11−# version: 0.11.20210101
11+# version: 0.15.20220609
12#
12#
13−# REGENDATA ("0.11.20210101",["github","cabal.project"])
13+# REGENDATA ("0.15.20220609",["github","cabal.project"])
14#
14#
15name: Haskell-CI
15name: Haskell-CI
16on:
16on:
@@ -22,60 +22,119 @@ on:
22 - master
22 - master
23jobs:
23jobs:
24 linux:
24 linux:
25− name: Haskell-CI Linux - GHC ${{ matrix.ghc }}
25+ name: Haskell-CI - Linux - ${{ matrix.compiler }}
26− runs-on: ubuntu-18.04
26+ runs-on: ubuntu-20.04
27+ timeout-minutes:
28+ 60
27 container:
29 container:
28 image: buildpack-deps:bionic
30 image: buildpack-deps:bionic
29 continue-on-error: ${{ matrix.allow-failure }}
31 continue-on-error: ${{ matrix.allow-failure }}
30 strategy:
32 strategy:
31 matrix:
33 matrix:
32 include:
34 include:
33− - ghc: 8.10.3
35+ - compiler: ghc-9.4.0.20220523
36+ compilerKind: ghc
37+ compilerVersion: 9.4.0.20220523
38+ setup-method: ghcup
39+ allow-failure: true
40+ - compiler: ghc-9.2.3
41+ compilerKind: ghc
42+ compilerVersion: 9.2.3
43+ setup-method: ghcup
34 allow-failure: false
44 allow-failure: false
35− - ghc: 8.8.4
45+ - compiler: ghc-9.0.2
46+ compilerKind: ghc
47+ compilerVersion: 9.0.2
48+ setup-method: ghcup
36 allow-failure: false
49 allow-failure: false
37− - ghc: 8.6.5
50+ - compiler: ghc-8.10.7
51+ compilerKind: ghc
52+ compilerVersion: 8.10.7
53+ setup-method: ghcup
38 allow-failure: false
54 allow-failure: false
39− - ghc: 8.4.4
55+ - compiler: ghc-8.8.4
56+ compilerKind: ghc
57+ compilerVersion: 8.8.4
58+ setup-method: hvr-ppa
40 allow-failure: false
59 allow-failure: false
41− - ghc: 8.2.2
60+ - compiler: ghc-8.6.5
61+ compilerKind: ghc
62+ compilerVersion: 8.6.5
63+ setup-method: hvr-ppa
42 allow-failure: false
64 allow-failure: false
43− - ghc: 8.0.2
65+ - compiler: ghc-8.4.4
66+ compilerKind: ghc
67+ compilerVersion: 8.4.4
68+ setup-method: hvr-ppa
44 allow-failure: false
69 allow-failure: false
45− - ghc: 7.10.3
70+ - compiler: ghc-8.2.2
71+ compilerKind: ghc
72+ compilerVersion: 8.2.2
73+ setup-method: hvr-ppa
46 allow-failure: false
74 allow-failure: false
47− - ghc: 7.8.4
75+ - compiler: ghc-8.0.2
76+ compilerKind: ghc
77+ compilerVersion: 8.0.2
78+ setup-method: hvr-ppa
48 allow-failure: false
79 allow-failure: false
49 fail-fast: false
80 fail-fast: false
50 steps:
81 steps:
51 - name: apt
82 - name: apt
52 run: |
83 run: |
53 apt-get update
84 apt-get update
54− apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
85+ apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
86+ if [ "${{ matrix.setup-method }}" = ghcup ]; then
87+ mkdir -p "$HOME/.ghcup/bin"
88+ curl -sL https://downloads.haskell.org/ghcup/0.1.17.8/x86_64-linux-ghcup-0.1.17.8 > "$HOME/.ghcup/bin/ghcup"
89+ chmod a+x "$HOME/.ghcup/bin/ghcup"
90+ if $HEADHACKAGE; then "$HOME/.ghcup/bin/ghcup" config add-release-channel https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml; fi
91+ "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
92+ "$HOME/.ghcup/bin/ghcup" install cabal 3.6.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
93+ else
55− apt-add-repository -y 'ppa:hvr/ghc'
94+ apt-add-repository -y 'ppa:hvr/ghc'
56− apt-get update
95+ apt-get update
57− apt-get install -y ghc-$GHC_VERSION cabal-install-3.2
96+ apt-get install -y "$HCNAME"
97+ mkdir -p "$HOME/.ghcup/bin"
98+ curl -sL https://downloads.haskell.org/ghcup/0.1.17.8/x86_64-linux-ghcup-0.1.17.8 > "$HOME/.ghcup/bin/ghcup"
99+ chmod a+x "$HOME/.ghcup/bin/ghcup"
100+ "$HOME/.ghcup/bin/ghcup" install cabal 3.6.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
101+ fi
58 env:
102 env:
59− GHC_VERSION: ${{ matrix.ghc }}
103+ HCKIND: ${{ matrix.compilerKind }}
104+ HCNAME: ${{ matrix.compiler }}
105+ HCVER: ${{ matrix.compilerVersion }}
60 - name: Set PATH and environment variables
106 - name: Set PATH and environment variables
61 run: |
107 run: |
62 echo "$HOME/.cabal/bin" >> $GITHUB_PATH
108 echo "$HOME/.cabal/bin" >> $GITHUB_PATH
63− echo "LANG=C.UTF-8" >> $GITHUB_ENV
109+ echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
64− echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
110+ echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
65− echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
111+ echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
66− HC=/opt/ghc/$GHC_VERSION/bin/ghc
112+ HCDIR=/opt/$HCKIND/$HCVER
113+ if [ "${{ matrix.setup-method }}" = ghcup ]; then
114+ HC=$HOME/.ghcup/bin/$HCKIND-$HCVER
67− echo "HC=$HC" >> $GITHUB_ENV
115+ echo "HC=$HC" >> "$GITHUB_ENV"
68− echo "HCPKG=/opt/ghc/$GHC_VERSION/bin/ghc-pkg" >> $GITHUB_ENV
116+ echo "HCPKG=$HOME/.ghcup/bin/$HCKIND-pkg-$HCVER" >> "$GITHUB_ENV"
69− echo "HADDOCK=/opt/ghc/$GHC_VERSION/bin/haddock" >> $GITHUB_ENV
117+ echo "HADDOCK=$HOME/.ghcup/bin/haddock-$HCVER" >> "$GITHUB_ENV"
118+ echo "CABAL=$HOME/.ghcup/bin/cabal-3.6.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
119+ else
120+ HC=$HCDIR/bin/$HCKIND
121+ echo "HC=$HC" >> "$GITHUB_ENV"
122+ echo "HCPKG=$HCDIR/bin/$HCKIND-pkg" >> "$GITHUB_ENV"
123+ echo "HADDOCK=$HCDIR/bin/haddock" >> "$GITHUB_ENV"
70− echo "CABAL=/opt/cabal/3.2/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
124+ echo "CABAL=$HOME/.ghcup/bin/cabal-3.6.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
125+ fi
126+
71 HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
127 HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
72− echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
128+ echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
73− echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
129+ echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
74− echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
130+ echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
131+ if [ $((HCNUMVER >= 90400)) -ne 0 ] ; then echo "HEADHACKAGE=true" >> "$GITHUB_ENV" ; else echo "HEADHACKAGE=false" >> "$GITHUB_ENV" ; fi
75− echo "ARG_COMPILER=--ghc --with-compiler=/opt/ghc/$GHC_VERSION/bin/ghc" >> $GITHUB_ENV
132+ echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
76− echo "GHCJSARITH=0" >> $GITHUB_ENV
133+ echo "GHCJSARITH=0" >> "$GITHUB_ENV"
77 env:
134 env:
78− GHC_VERSION: ${{ matrix.ghc }}
135+ HCKIND: ${{ matrix.compilerKind }}
136+ HCNAME: ${{ matrix.compiler }}
137+ HCVER: ${{ matrix.compilerVersion }}
79 - name: env
138 - name: env
80 run: |
139 run: |
81 env
140 env
@@ -98,6 +157,22 @@ jobs:
98 repository hackage.haskell.org
157 repository hackage.haskell.org
99 url: http://hackage.haskell.org/
158 url: http://hackage.haskell.org/
100 EOF
159 EOF
160+ if $HEADHACKAGE; then
161+ cat >> $CABAL_CONFIG <<EOF
162+ repository head.hackage.ghc.haskell.org
163+ url: https://ghc.gitlab.haskell.org/head.hackage/
164+ secure: True
165+ root-keys: 7541f32a4ccca4f97aea3b22f5e593ba2c0267546016b992dfadcd2fe944e55d
166+ 26021a13b401500c8eb2761ca95c61f2d625bfef951b939a8124ed12ecf07329
167+ f76d08be13e9a61a377a85e2fb63f4c5435d40f8feb3e12eb05905edb8cdea89
168+ key-threshold: 3
169+ active-repositories: hackage.haskell.org, head.hackage.ghc.haskell.org:override
170+ EOF
171+ fi
172+ cat >> $CABAL_CONFIG <<EOF
173+ program-default-options
174+ ghc-options: $GHCJOBS +RTS -M3G -RTS
175+ EOF
101 cat $CABAL_CONFIG
176 cat $CABAL_CONFIG
102 - name: versions
177 - name: versions
103 run: |
178 run: |
@@ -110,7 +185,7 @@ jobs:
110 - name: cache (tools)
185 - name: cache (tools)
111 uses: actions/cache@v2
186 uses: actions/cache@v2
112 with:
187 with:
113− key: ${{ runner.os }}-${{ matrix.ghc }}-tools-0f645703
188+ key: ${{ runner.os }}-${{ matrix.compiler }}-tools-445c2459
114 path: ~/.haskell-ci-tools
189 path: ~/.haskell-ci-tools
115 - name: install cabal-plan
190 - name: install cabal-plan
116 run: |
191 run: |
@@ -123,16 +198,20 @@ jobs:
123 cabal-plan --version
198 cabal-plan --version
124 - name: install doctest
199 - name: install doctest
125 run: |
200 run: |
126− if [ $((HCNUMVER >= 80000 && HCNUMVER < 81000)) -ne 0 ] ; then $CABAL --store-dir=$HOME/.haskell-ci-tools/store v2-install $ARG_COMPILER --ignore-project -j2 doctest --constraint='doctest ^>=0.17' ; fi
201+ if [ $((HCNUMVER < 90000)) -ne 0 ] ; then $CABAL --store-dir=$HOME/.haskell-ci-tools/store v2-install $ARG_COMPILER --ignore-project -j2 doctest --constraint='doctest ^>=0.20' ; fi
127− if [ $((HCNUMVER >= 80000 && HCNUMVER < 81000)) -ne 0 ] ; then doctest --version ; fi
202+ if [ $((HCNUMVER < 90000)) -ne 0 ] ; then doctest --version ; fi
128 - name: checkout
203 - name: checkout
129 uses: actions/checkout@v2
204 uses: actions/checkout@v2
130 with:
205 with:
131 path: source
206 path: source
207+ - name: initial cabal.project for sdist
208+ run: |
209+ touch cabal.project
210+ echo "packages: $GITHUB_WORKSPACE/source/." >> cabal.project
211+ cat cabal.project
132 - name: sdist
212 - name: sdist
133 run: |
213 run: |
134 mkdir -p sdist
214 mkdir -p sdist
135− cd source || false
136 $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
215 $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
137 - name: unpack
216 - name: unpack
138 run: |
217 run: |
@@ -141,7 +220,8 @@ jobs:
141 - name: generate cabal.project
220 - name: generate cabal.project
142 run: |
221 run: |
143 PKGDIR_http_api_data="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/http-api-data-[0-9.]*')"
222 PKGDIR_http_api_data="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/http-api-data-[0-9.]*')"
144− echo "PKGDIR_http_api_data=${PKGDIR_http_api_data}" >> $GITHUB_ENV
223+ echo "PKGDIR_http_api_data=${PKGDIR_http_api_data}" >> "$GITHUB_ENV"
224+ rm -f cabal.project cabal.project.local
145 touch cabal.project
225 touch cabal.project
146 touch cabal.project.local
226 touch cabal.project.local
147 echo "packages: ${PKGDIR_http_api_data}" >> cabal.project
227 echo "packages: ${PKGDIR_http_api_data}" >> cabal.project
@@ -149,6 +229,9 @@ jobs:
149 if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo " ghc-options: -Werror=missing-methods" >> cabal.project ; fi
229 if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo " ghc-options: -Werror=missing-methods" >> cabal.project ; fi
150 cat >> cabal.project <<EOF
230 cat >> cabal.project <<EOF
151 EOF
231 EOF
232+ if $HEADHACKAGE; then
233+ echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1,/g')" >> cabal.project
234+ fi
152 $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(http-api-data)$/; }' >> cabal.project.local
235 $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(http-api-data)$/; }' >> cabal.project.local
153 cat cabal.project
236 cat cabal.project
154 cat cabal.project.local
237 cat cabal.project.local
@@ -159,9 +242,9 @@ jobs:
159 - name: cache
242 - name: cache
160 uses: actions/cache@v2
243 uses: actions/cache@v2
161 with:
244 with:
162− key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }}
245+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
163 path: ~/.cabal/store
246 path: ~/.cabal/store
164− restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
247+ restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
165 - name: install dependencies
248 - name: install dependencies
166 run: |
249 run: |
167 $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
250 $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
@@ -178,15 +261,15 @@ jobs:
178 - name: doctest
261 - name: doctest
179 run: |
262 run: |
180 perl -i -e 'while (<ARGV>) { print unless /package-id\s+(base-compat)-\d+(\.\d+)*/; }' .ghc.environment.*
263 perl -i -e 'while (<ARGV>) { print unless /package-id\s+(base-compat)-\d+(\.\d+)*/; }' .ghc.environment.*
181− if [ $((HCNUMVER >= 80000 && HCNUMVER < 81000)) -ne 0 ] ; then cd ${PKGDIR_http_api_data} || false ; fi
264+ if [ $((HCNUMVER < 90000)) -ne 0 ] ; then cd ${PKGDIR_http_api_data} || false ; fi
182− if [ $((HCNUMVER >= 80000 && HCNUMVER < 81000)) -ne 0 ] ; then doctest src/ ; fi
265+ if [ $((HCNUMVER < 90000)) -ne 0 ] ; then doctest -XHaskell2010 src/ ; fi
183 - name: cabal check
266 - name: cabal check
184 run: |
267 run: |
185 cd ${PKGDIR_http_api_data} || false
268 cd ${PKGDIR_http_api_data} || false
186 ${CABAL} -vnormal check
269 ${CABAL} -vnormal check
187 - name: haddock
270 - name: haddock
188 run: |
271 run: |
189− $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
272+ $CABAL v2-haddock --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
190 - name: unconstrained build
273 - name: unconstrained build
191 run: |
274 run: |
192 rm -f cabal.project.local
275 rm -f cabal.project.local
@@ -196,4 +279,5 @@ jobs:
196 rm -f cabal.project.local
279 rm -f cabal.project.local
197 - name: constraint set text-show
280 - name: constraint set text-show
198 run: |
281 run: |
282+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='http-api-data +use-text-show' --dependencies-only -j2 all
199 $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='http-api-data +use-text-show' all
283 $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='http-api-data +use-text-show' all
CHANGELOG.md+13
@@ -1,3 +1,16 @@
1+0.5
2+---
3+
4+* Use `attoparsec-iso8601-1.1.0.0`.
5+ `Day` and `UTCTime` parsers require at least 4 digits now, which is a breaking change.
6+* Drop GHC-7.8 and GHC-7.10 support.
7+
8+0.4.3
9+-----
10+
11+* Add `Quarter`, `QuarterOfYear` and `Month` instances
12+* Support `bytestring-0.11`
13+
10.4.2
140.4.2
2-----
15-----
3
16
cabal.haskell-ci+1−1
@@ -1,5 +1,5 @@
1branches: master
1branches: master
2−doctest: <8.10
2+doctest: <9
3doctest-filter-packages: base-compat
3doctest-filter-packages: base-compat
4
4
5constraint-set text-show
5constraint-set text-show
http-api-data.cabal+23−34
@@ -1,6 +1,6 @@
1cabal-version: >= 1.10
1cabal-version: >= 1.10
2name: http-api-data
2name: http-api-data
3−version: 0.4.2
3+version: 0.5
4
4
5synopsis: Converting to/from HTTP API data like URL pieces, headers and query parameters.
5synopsis: Converting to/from HTTP API data like URL pieces, headers and query parameters.
6category: Web
6category: Web
@@ -24,14 +24,15 @@ extra-source-files:
24 README.md
24 README.md
25
25
26tested-with:
26tested-with:
27− GHC==7.8.4,
28− GHC==7.10.3,
29 GHC==8.0.2,
27 GHC==8.0.2,
30 GHC==8.2.2,
28 GHC==8.2.2,
31 GHC==8.4.4,
29 GHC==8.4.4,
32 GHC==8.6.5,
30 GHC==8.6.5,
33 GHC==8.8.4,
31 GHC==8.8.4,
34− GHC==8.10.3
32+ GHC==8.10.7,
33+ GHC==9.0.2,
34+ GHC==9.2.3,
35+ GHC==9.4.1
35
36
36flag use-text-show
37flag use-text-show
37 description: Use text-show library for efficient ToHttpApiData implementations.
38 description: Use text-show library for efficient ToHttpApiData implementations.
@@ -43,40 +44,28 @@ library
43 include-dirs: include/
44 include-dirs: include/
44
45
45 -- GHC bundled
46 -- GHC bundled
46− build-depends: base >= 4.7 && < 4.15
47+ build-depends: base >= 4.9 && < 4.17
47− , bytestring >= 0.10.4.0 && < 0.11
48+ , bytestring >= 0.10.8.1 && < 0.12
48− , containers >= 0.5.5.1 && < 0.7
49+ , containers >= 0.5.7.1 && < 0.7
49− , text >= 1.2.3.0 && < 1.3
50+ , text >= 1.2.3.0 && < 1.3 || >=2.0 && <2.1
50− , transformers >= 0.3 && < 0.6
51+ , transformers >= 0.5.2.0 && < 0.7
51−
52− -- so Semigroup Builder exists
53− if impl(ghc >= 8.0)
54− build-depends: bytestring >= 0.10.8.1
55
52
56 -- other-dependencies
53 -- other-dependencies
57 build-depends:
54 build-depends:
58− attoparsec >= 0.13.2.2 && < 0.14
55+ attoparsec >= 0.13.2.2 && < 0.15
59− , attoparsec-iso8601 >= 1.0.1.0 && < 1.1
56+ , attoparsec-iso8601 >= 1.1.0.0 && < 1.2
60− , base-compat >= 0.10.5 && < 0.12
57+ , base-compat >= 0.10.5 && < 0.13
61 , cookie >= 0.4.3 && < 0.5
58 , cookie >= 0.4.3 && < 0.5
62− , hashable >= 1.2.7.0 && < 1.4
59+ , hashable >= 1.2.7.0 && < 1.5
63 , http-types >= 0.12.3 && < 0.13
60 , http-types >= 0.12.3 && < 0.13
64 , tagged >= 0.8.5 && < 0.9
61 , tagged >= 0.8.5 && < 0.9
65− , time-compat >= 1.9.2 && < 1.10
62+ , time-compat >= 1.9.5 && < 1.10
66− , unordered-containers >= 0.2.10.0 && < 0.3
63+ , unordered-containers >= 0.2.10.0 && < 0.3
67− , uuid-types >= 1.0.3 && <1.1
64+ , uuid-types >= 1.0.3 && < 1.1
68−
69− if !impl(ghc >= 7.10)
70− build-depends:
71− nats >= 1.1.2 && < 1.2,
72− void >= 0.7.3 && < 0.8
73−
74− if !impl(ghc >= 8.0)
75− build-depends: semigroups >= 0.18.5 && < 0.20
76
65
77 if flag(use-text-show)
66 if flag(use-text-show)
78 cpp-options: -DUSE_TEXT_SHOW
67 cpp-options: -DUSE_TEXT_SHOW
79− build-depends: text-show >= 3.8.2 && <3.9
68+ build-depends: text-show >= 3.8.2 && <3.10
80
69
81 exposed-modules:
70 exposed-modules:
82 Web.HttpApiData
71 Web.HttpApiData
@@ -96,7 +85,7 @@ test-suite spec
96 hs-source-dirs: test
85 hs-source-dirs: test
97 ghc-options: -Wall
86 ghc-options: -Wall
98 default-language: Haskell2010
87 default-language: Haskell2010
99− build-tool-depends: hspec-discover:hspec-discover >= 2.7.1 && <2.8
88+ build-tool-depends: hspec-discover:hspec-discover >= 2.7.1 && <2.11
100 -- inherited depndencies
89 -- inherited depndencies
101 build-depends:
90 build-depends:
102 base
91 base
@@ -112,10 +101,10 @@ test-suite spec
112 if !impl(ghc >= 7.10)
101 if !impl(ghc >= 7.10)
113 build-depends: nats
102 build-depends: nats
114
103
115− build-depends: HUnit >= 1.6.0.0 && <1.7
104+ build-depends: HUnit >= 1.6.0.0 && <1.7
116− , hspec >= 2.7.1 && <2.8
105+ , hspec >= 2.7.1 && <2.11
117− , QuickCheck >= 2.13.1 && <2.15
106+ , QuickCheck >= 2.13.1 && <2.15
118− , quickcheck-instances >= 0.3.21 && <0.4
107+ , quickcheck-instances >= 0.3.25.2 && <0.4
119
108
120source-repository head
109source-repository head
121 type: git
110 type: git
src/Web/Internal/FormUrlEncoded.hs+8
@@ -52,6 +52,8 @@ import Data.Text.Encoding.Error (lenientDecode)
52import qualified Data.Text.Lazy as Lazy
52import qualified Data.Text.Lazy as Lazy
53import Data.Time.Compat (Day, LocalTime, NominalDiffTime,
53import Data.Time.Compat (Day, LocalTime, NominalDiffTime,
54 UTCTime, ZonedTime)
54 UTCTime, ZonedTime)
55+import Data.Time.Calendar.Month.Compat (Month)
56+import Data.Time.Calendar.Quarter.Compat (Quarter, QuarterOfYear (..))
55import Data.Void (Void)
57import Data.Void (Void)
56import Data.Word (Word16, Word32, Word64, Word8)
58import Data.Word (Word16, Word32, Word64, Word8)
57import GHC.Exts (Constraint, IsList (..))
59import GHC.Exts (Constraint, IsList (..))
@@ -113,6 +115,9 @@ instance ToFormKey LocalTime where toFormKey = toQueryParam
113instance ToFormKey ZonedTime where toFormKey = toQueryParam
115instance ToFormKey ZonedTime where toFormKey = toQueryParam
114instance ToFormKey UTCTime where toFormKey = toQueryParam
116instance ToFormKey UTCTime where toFormKey = toQueryParam
115instance ToFormKey NominalDiffTime where toFormKey = toQueryParam
117instance ToFormKey NominalDiffTime where toFormKey = toQueryParam
118+instance ToFormKey Quarter where toFormKey = toQueryParam
119+instance ToFormKey QuarterOfYear where toFormKey = toQueryParam
120+instance ToFormKey Month where toFormKey = toQueryParam
116
121
117instance ToFormKey String where toFormKey = toQueryParam
122instance ToFormKey String where toFormKey = toQueryParam
118instance ToFormKey Text where toFormKey = toQueryParam
123instance ToFormKey Text where toFormKey = toQueryParam
@@ -172,6 +177,9 @@ instance FromFormKey LocalTime where parseFormKey = parseQueryParam
172instance FromFormKey ZonedTime where parseFormKey = parseQueryParam
177instance FromFormKey ZonedTime where parseFormKey = parseQueryParam
173instance FromFormKey UTCTime where parseFormKey = parseQueryParam
178instance FromFormKey UTCTime where parseFormKey = parseQueryParam
174instance FromFormKey NominalDiffTime where parseFormKey = parseQueryParam
179instance FromFormKey NominalDiffTime where parseFormKey = parseQueryParam
180+instance FromFormKey Quarter where parseFormKey = parseQueryParam
181+instance FromFormKey QuarterOfYear where parseFormKey = parseQueryParam
182+instance FromFormKey Month where parseFormKey = parseQueryParam
175
183
176instance FromFormKey String where parseFormKey = parseQueryParam
184instance FromFormKey String where parseFormKey = parseQueryParam
177instance FromFormKey Text where parseFormKey = parseQueryParam
185instance FromFormKey Text where parseFormKey = parseQueryParam
src/Web/Internal/HttpApiData.hs+68−9
@@ -32,6 +32,7 @@ import Data.Data (Data)
32import qualified Data.Fixed as F
32import qualified Data.Fixed as F
33import Data.Functor.Identity (Identity(Identity))
33import Data.Functor.Identity (Identity(Identity))
34import Data.Int (Int16, Int32, Int64, Int8)
34import Data.Int (Int16, Int32, Int64, Int8)
35+import Data.Kind (Type)
35import qualified Data.Map as Map
36import qualified Data.Map as Map
36import Data.Monoid (All (..), Any (..), Dual (..),
37import Data.Monoid (All (..), Any (..), Dual (..),
37 First (..), Last (..),
38 First (..), Last (..),
@@ -55,6 +56,9 @@ import Data.Time.Compat (Day, FormatTime, LocalTime,
55 secondsToNominalDiffTime)
56 secondsToNominalDiffTime)
56import Data.Time.Format.Compat (defaultTimeLocale,
57import Data.Time.Format.Compat (defaultTimeLocale,
57 iso8601DateFormat)
58 iso8601DateFormat)
59+import Data.Time.Calendar.Month.Compat (Month)
60+import Data.Time.Calendar.Quarter.Compat (Quarter, QuarterOfYear (..),
61+ toYearQuarter)
58import Data.Typeable (Typeable)
62import Data.Typeable (Typeable)
59import qualified Data.UUID.Types as UUID
63import qualified Data.UUID.Types as UUID
60import Data.Version (Version, parseVersion,
64import Data.Version (Version, parseVersion,
@@ -68,12 +72,6 @@ import Text.Read (readMaybe)
68import Web.Cookie (SetCookie, parseSetCookie,
72import Web.Cookie (SetCookie, parseSetCookie,
69 renderSetCookie)
73 renderSetCookie)
70
74
71−#if MIN_VERSION_base(4,9,0)
72−import Data.Kind (Type)
73−#else
74−#define Type *
75−#endif
76−
77#if USE_TEXT_SHOW
75#if USE_TEXT_SHOW
78import TextShow (TextShow, showt)
76import TextShow (TextShow, showt)
79#endif
77#endif
@@ -98,7 +96,7 @@ class ToHttpApiData a where
98 -- The default definition uses 'H.encodePathSegmentsRelative',
96 -- The default definition uses 'H.encodePathSegmentsRelative',
99 -- but this may be overriden with a more efficient version.
97 -- but this may be overriden with a more efficient version.
100 toEncodedUrlPiece :: a -> BS.Builder
98 toEncodedUrlPiece :: a -> BS.Builder
101− toEncodedUrlPiece = H.encodePathSegmentsRelative . (:[]) . toUrlPiece
99+ toEncodedUrlPiece = H.urlEncodeBuilder True . encodeUtf8 . toUrlPiece
102
100
103 -- | Convert to HTTP header value.
101 -- | Convert to HTTP header value.
104 toHeader :: a -> ByteString
102 toHeader :: a -> ByteString
@@ -516,6 +514,42 @@ instance ToHttpApiData DayOfWeek where
516
514
517 toEncodedUrlPiece = unsafeToEncodedUrlPiece
515 toEncodedUrlPiece = unsafeToEncodedUrlPiece
518
516
517+-- |
518+-- >>> toUrlPiece Q4
519+-- "q4"
520+instance ToHttpApiData QuarterOfYear where
521+ toUrlPiece Q1 = "q1"
522+ toUrlPiece Q2 = "q2"
523+ toUrlPiece Q3 = "q3"
524+ toUrlPiece Q4 = "q4"
525+
526+-- |
527+-- >>> import Data.Time.Calendar.Quarter.Compat (Quarter (..))
528+-- >>> MkQuarter 8040
529+-- 2010-Q1
530+--
531+-- >>> toUrlPiece $ MkQuarter 8040
532+-- "2010-q1"
533+--
534+instance ToHttpApiData Quarter where
535+ toUrlPiece q = case toYearQuarter q of
536+ (y, qoy) -> T.pack (show y ++ "-" ++ f qoy)
537+ where
538+ f Q1 = "q1"
539+ f Q2 = "q2"
540+ f Q3 = "q3"
541+ f Q4 = "q4"
542+
543+-- |
544+-- >>> import Data.Time.Calendar.Month.Compat (Month (..))
545+-- >>> MkMonth 24482
546+-- 2040-03
547+--
548+-- >>> toUrlPiece $ MkMonth 24482
549+-- "2040-03"
550+--
551+instance ToHttpApiData Month where
552+ toUrlPiece = T.pack . formatTime defaultTimeLocale "%Y-%m"
519
553
520instance ToHttpApiData NominalDiffTime where
554instance ToHttpApiData NominalDiffTime where
521 toUrlPiece = toUrlPiece . nominalDiffTimeToSeconds
555 toUrlPiece = toUrlPiece . nominalDiffTimeToSeconds
@@ -704,6 +738,9 @@ instance FromHttpApiData ZonedTime where parseUrlPiece = runAtto Atto.zonedTime
704-- Right 2015-10-03 00:14:24 UTC
738-- Right 2015-10-03 00:14:24 UTC
705instance FromHttpApiData UTCTime where parseUrlPiece = runAtto Atto.utcTime
739instance FromHttpApiData UTCTime where parseUrlPiece = runAtto Atto.utcTime
706
740
741+-- |
742+-- >>> parseUrlPiece "Monday" :: Either Text DayOfWeek
743+-- Right Monday
707instance FromHttpApiData DayOfWeek where
744instance FromHttpApiData DayOfWeek where
708 parseUrlPiece t = case Map.lookup (T.toLower t) m of
745 parseUrlPiece t = case Map.lookup (T.toLower t) m of
709 Just dow -> Right dow
746 Just dow -> Right dow
@@ -715,6 +752,30 @@ instance FromHttpApiData DayOfWeek where
715
752
716instance FromHttpApiData NominalDiffTime where parseUrlPiece = fmap secondsToNominalDiffTime . parseUrlPiece
753instance FromHttpApiData NominalDiffTime where parseUrlPiece = fmap secondsToNominalDiffTime . parseUrlPiece
717
754
755+-- |
756+-- >>> parseUrlPiece "2021-01" :: Either Text Month
757+-- Right 2021-01
758+instance FromHttpApiData Month where parseUrlPiece = runAtto Atto.month
759+
760+-- |
761+-- >>> parseUrlPiece "2021-q1" :: Either Text Quarter
762+-- Right 2021-Q1
763+instance FromHttpApiData Quarter where parseUrlPiece = runAtto Atto.quarter
764+
765+-- |
766+-- >>> parseUrlPiece "q2" :: Either Text QuarterOfYear
767+-- Right Q2
768+--
769+-- >>> parseUrlPiece "Q3" :: Either Text QuarterOfYear
770+-- Right Q3
771+instance FromHttpApiData QuarterOfYear where
772+ parseUrlPiece t = case T.toLower t of
773+ "q1" -> return Q1
774+ "q2" -> return Q2
775+ "q3" -> return Q3
776+ "q4" -> return Q4
777+ _ -> Left "Invalid quarter of year"
778+
718instance FromHttpApiData All where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
779instance FromHttpApiData All where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
719instance FromHttpApiData Any where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
780instance FromHttpApiData Any where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
720
781
@@ -804,5 +865,3 @@ runAtto :: Atto.Parser a -> Text -> Either Text a
804runAtto p t = case Atto.parseOnly (p <* Atto.endOfInput) t of
865runAtto p t = case Atto.parseOnly (p <* Atto.endOfInput) t of
805 Left err -> Left (T.pack err)
866 Left err -> Left (T.pack err)
806 Right x -> Right x
867 Right x -> Right x
807−
808−
test/Web/Internal/HttpApiDataSpec.hs+6
@@ -14,6 +14,8 @@ import qualified Data.Text as T
14import qualified Data.Text.Encoding as TE
14import qualified Data.Text.Encoding as TE
15import qualified Data.Text.Lazy as L
15import qualified Data.Text.Lazy as L
16import Data.Time.Compat
16import Data.Time.Compat
17+import Data.Time.Calendar.Month.Compat (Month)
18+import Data.Time.Calendar.Quarter.Compat (Quarter, QuarterOfYear (..))
17import qualified Data.UUID.Types as UUID
19import qualified Data.UUID.Types as UUID
18import Data.Version
20import Data.Version
19import Data.Word
21import Data.Word
@@ -87,6 +89,10 @@ spec = do
87 checkUrlPiece (Proxy :: Proxy UTCTime) "UTCTime"
89 checkUrlPiece (Proxy :: Proxy UTCTime) "UTCTime"
88 checkUrlPiece (Proxy :: Proxy NominalDiffTime) "NominalDiffTime"
90 checkUrlPiece (Proxy :: Proxy NominalDiffTime) "NominalDiffTime"
89 checkUrlPiece (Proxy :: Proxy DayOfWeek) "DayOfWeek"
91 checkUrlPiece (Proxy :: Proxy DayOfWeek) "DayOfWeek"
92+ checkUrlPiece (Proxy :: Proxy Quarter) "Quarter"
93+ checkUrlPiece (Proxy :: Proxy QuarterOfYear) "QuarterOfYear"
94+ checkUrlPiece (Proxy :: Proxy Month) "Month"
95+ checkUrlPiece (Proxy :: Proxy DayOfWeek) "DayOfWeek"
90 checkUrlPiece (Proxy :: Proxy Version) "Version"
96 checkUrlPiece (Proxy :: Proxy Version) "Version"
91 checkUrlPiece (Proxy :: Proxy UUID.UUID) "UUID"
97 checkUrlPiece (Proxy :: Proxy UUID.UUID) "UUID"
92 checkUrlPiece' setCookieGen "Cookie"
98 checkUrlPiece' setCookieGen "Cookie"