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.ymlnew file+283
@@ -0,0 +1,283 @@
1+# This GitHub workflow config has been generated by a script via
2+#
3+# haskell-ci 'github' 'cabal.project'
4+#
5+# To regenerate the script (for example after adjusting tested-with) run
6+#
7+# haskell-ci regenerate
8+#
9+# For more information, see https://github.com/haskell-CI/haskell-ci
10+#
11+# version: 0.15.20220609
12+#
13+# REGENDATA ("0.15.20220609",["github","cabal.project"])
14+#
15+name: Haskell-CI
16+on:
17+ push:
18+ branches:
19+ - master
20+ pull_request:
21+ branches:
22+ - master
23+jobs:
24+ linux:
25+ name: Haskell-CI - Linux - ${{ matrix.compiler }}
26+ runs-on: ubuntu-20.04
27+ timeout-minutes:
28+ 60
29+ container:
30+ image: buildpack-deps:bionic
31+ continue-on-error: ${{ matrix.allow-failure }}
32+ strategy:
33+ matrix:
34+ include:
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
44+ allow-failure: false
45+ - compiler: ghc-9.0.2
46+ compilerKind: ghc
47+ compilerVersion: 9.0.2
48+ setup-method: ghcup
49+ allow-failure: false
50+ - compiler: ghc-8.10.7
51+ compilerKind: ghc
52+ compilerVersion: 8.10.7
53+ setup-method: ghcup
54+ allow-failure: false
55+ - compiler: ghc-8.8.4
56+ compilerKind: ghc
57+ compilerVersion: 8.8.4
58+ setup-method: hvr-ppa
59+ allow-failure: false
60+ - compiler: ghc-8.6.5
61+ compilerKind: ghc
62+ compilerVersion: 8.6.5
63+ setup-method: hvr-ppa
64+ allow-failure: false
65+ - compiler: ghc-8.4.4
66+ compilerKind: ghc
67+ compilerVersion: 8.4.4
68+ setup-method: hvr-ppa
69+ allow-failure: false
70+ - compiler: ghc-8.2.2
71+ compilerKind: ghc
72+ compilerVersion: 8.2.2
73+ setup-method: hvr-ppa
74+ allow-failure: false
75+ - compiler: ghc-8.0.2
76+ compilerKind: ghc
77+ compilerVersion: 8.0.2
78+ setup-method: hvr-ppa
79+ allow-failure: false
80+ fail-fast: false
81+ steps:
82+ - name: apt
83+ run: |
84+ apt-get update
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
94+ apt-add-repository -y 'ppa:hvr/ghc'
95+ apt-get update
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
102+ env:
103+ HCKIND: ${{ matrix.compilerKind }}
104+ HCNAME: ${{ matrix.compiler }}
105+ HCVER: ${{ matrix.compilerVersion }}
106+ - name: Set PATH and environment variables
107+ run: |
108+ echo "$HOME/.cabal/bin" >> $GITHUB_PATH
109+ echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
110+ echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
111+ echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
112+ HCDIR=/opt/$HCKIND/$HCVER
113+ if [ "${{ matrix.setup-method }}" = ghcup ]; then
114+ HC=$HOME/.ghcup/bin/$HCKIND-$HCVER
115+ echo "HC=$HC" >> "$GITHUB_ENV"
116+ echo "HCPKG=$HOME/.ghcup/bin/$HCKIND-pkg-$HCVER" >> "$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"
124+ echo "CABAL=$HOME/.ghcup/bin/cabal-3.6.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
125+ fi
126+
127+ HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
128+ echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
129+ echo "ARG_TESTS=--enable-tests" >> "$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
132+ echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
133+ echo "GHCJSARITH=0" >> "$GITHUB_ENV"
134+ env:
135+ HCKIND: ${{ matrix.compilerKind }}
136+ HCNAME: ${{ matrix.compiler }}
137+ HCVER: ${{ matrix.compilerVersion }}
138+ - name: env
139+ run: |
140+ env
141+ - name: write cabal config
142+ run: |
143+ mkdir -p $CABAL_DIR
144+ cat >> $CABAL_CONFIG <<EOF
145+ remote-build-reporting: anonymous
146+ write-ghc-environment-files: never
147+ remote-repo-cache: $CABAL_DIR/packages
148+ logs-dir: $CABAL_DIR/logs
149+ world-file: $CABAL_DIR/world
150+ extra-prog-path: $CABAL_DIR/bin
151+ symlink-bindir: $CABAL_DIR/bin
152+ installdir: $CABAL_DIR/bin
153+ build-summary: $CABAL_DIR/logs/build.log
154+ store-dir: $CABAL_DIR/store
155+ install-dirs user
156+ prefix: $CABAL_DIR
157+ repository hackage.haskell.org
158+ url: http://hackage.haskell.org/
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
176+ cat $CABAL_CONFIG
177+ - name: versions
178+ run: |
179+ $HC --version || true
180+ $HC --print-project-git-commit-id || true
181+ $CABAL --version || true
182+ - name: update cabal index
183+ run: |
184+ $CABAL v2-update -v
185+ - name: cache (tools)
186+ uses: actions/cache@v2
187+ with:
188+ key: ${{ runner.os }}-${{ matrix.compiler }}-tools-445c2459
189+ path: ~/.haskell-ci-tools
190+ - name: install cabal-plan
191+ run: |
192+ mkdir -p $HOME/.cabal/bin
193+ curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
194+ echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc cabal-plan.xz' | sha256sum -c -
195+ xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
196+ rm -f cabal-plan.xz
197+ chmod a+x $HOME/.cabal/bin/cabal-plan
198+ cabal-plan --version
199+ - name: install doctest
200+ run: |
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
202+ if [ $((HCNUMVER < 90000)) -ne 0 ] ; then doctest --version ; fi
203+ - name: checkout
204+ uses: actions/checkout@v2
205+ with:
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
212+ - name: sdist
213+ run: |
214+ mkdir -p sdist
215+ $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
216+ - name: unpack
217+ run: |
218+ mkdir -p unpacked
219+ find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
220+ - name: generate cabal.project
221+ run: |
222+ PKGDIR_http_api_data="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/http-api-data-[0-9.]*')"
223+ echo "PKGDIR_http_api_data=${PKGDIR_http_api_data}" >> "$GITHUB_ENV"
224+ rm -f cabal.project cabal.project.local
225+ touch cabal.project
226+ touch cabal.project.local
227+ echo "packages: ${PKGDIR_http_api_data}" >> cabal.project
228+ if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo "package http-api-data" >> cabal.project ; fi
229+ if [ $((HCNUMVER >= 80200)) -ne 0 ] ; then echo " ghc-options: -Werror=missing-methods" >> cabal.project ; fi
230+ cat >> cabal.project <<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
235+ $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(http-api-data)$/; }' >> cabal.project.local
236+ cat cabal.project
237+ cat cabal.project.local
238+ - name: dump install plan
239+ run: |
240+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
241+ cabal-plan
242+ - name: cache
243+ uses: actions/cache@v2
244+ with:
245+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
246+ path: ~/.cabal/store
247+ restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
248+ - name: install dependencies
249+ run: |
250+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
251+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
252+ - name: build w/o tests
253+ run: |
254+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
255+ - name: build
256+ run: |
257+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
258+ - name: tests
259+ run: |
260+ $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
261+ - name: doctest
262+ run: |
263+ perl -i -e 'while (<ARGV>) { print unless /package-id\s+(base-compat)-\d+(\.\d+)*/; }' .ghc.environment.*
264+ if [ $((HCNUMVER < 90000)) -ne 0 ] ; then cd ${PKGDIR_http_api_data} || false ; fi
265+ if [ $((HCNUMVER < 90000)) -ne 0 ] ; then doctest -XHaskell2010 src/ ; fi
266+ - name: cabal check
267+ run: |
268+ cd ${PKGDIR_http_api_data} || false
269+ ${CABAL} -vnormal check
270+ - name: haddock
271+ run: |
272+ $CABAL v2-haddock --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
273+ - name: unconstrained build
274+ run: |
275+ rm -f cabal.project.local
276+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
277+ - name: prepare for constraint sets
278+ run: |
279+ rm -f cabal.project.local
280+ - name: constraint set text-show
281+ run: |
282+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='http-api-data +use-text-show' --dependencies-only -j2 all
283+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='http-api-data +use-text-show' all
.travis.ymldeleted−171
@@ -1,171 +0,0 @@
1−# This Travis job script has been generated by a script via
2−#
3−# haskell-ci '--config=cabal.haskell-ci' 'http-api-data.cabal'
4−#
5−# For more information, see https://github.com/haskell-CI/haskell-ci
6−#
7−# version: 0.3.20190521
8−#
9−language: c
10−dist: xenial
11−git:
12− # whether to recursively clone submodules
13− submodules: false
14−branches:
15− only:
16− - master
17−cache:
18− directories:
19− - $HOME/.cabal/packages
20− - $HOME/.cabal/store
21−before_cache:
22− - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
23− # remove files that are regenerated by 'cabal update'
24− - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
25− - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
26− - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
27− - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
28− - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
29− - rm -rfv $CABALHOME/packages/head.hackage
30−matrix:
31− include:
32− - compiler: ghc-8.8.1
33− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.8.1","cabal-install-3.0"]}}
34− env: GHCHEAD=true
35− - compiler: ghc-8.6.5
36− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.6.5","cabal-install-2.4"]}}
37− - compiler: ghc-8.4.4
38− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.4.4","cabal-install-2.4"]}}
39− - compiler: ghc-8.2.2
40− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.2.2","cabal-install-2.4"]}}
41− - compiler: ghc-8.0.2
42− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.0.2","cabal-install-2.4"]}}
43− - compiler: ghc-7.10.3
44− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-7.10.3","cabal-install-2.4"]}}
45− - compiler: ghc-7.8.4
46− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-7.8.4","cabal-install-2.4"]}}
47− allow_failures:
48− - compiler: ghc-8.8.1
49−before_install:
50− - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
51− - HCPKG="$HC-pkg"
52− - unset CC
53− - CABAL=/opt/ghc/bin/cabal
54− - CABALHOME=$HOME/.cabal
55− - export PATH="$CABALHOME/bin:$PATH"
56− - TOP=$(pwd)
57− - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))
58− - echo $HCNUMVER
59− - CABAL="$CABAL -vnormal+nowrap+markoutput"
60− - set -o pipefail
61− - |
62− echo 'function blue(s) { printf "\033[0;34m" s "\033[0m " }' >> .colorful.awk
63− echo 'BEGIN { state = "output"; }' >> .colorful.awk
64− echo '/^-----BEGIN CABAL OUTPUT-----$/ { state = "cabal" }' >> .colorful.awk
65− echo '/^-----END CABAL OUTPUT-----$/ { state = "output" }' >> .colorful.awk
66− echo '!/^(-----BEGIN CABAL OUTPUT-----|-----END CABAL OUTPUT-----)/ {' >> .colorful.awk
67− echo ' if (state == "cabal") {' >> .colorful.awk
68− echo ' print blue($0)' >> .colorful.awk
69− echo ' } else {' >> .colorful.awk
70− echo ' print $0' >> .colorful.awk
71− echo ' }' >> .colorful.awk
72− echo '}' >> .colorful.awk
73− - cat .colorful.awk
74− - |
75− color_cabal_output () {
76− awk -f $TOP/.colorful.awk
77− }
78− - echo text | color_cabal_output
79−install:
80− - ${CABAL} --version
81− - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
82− - TEST=--enable-tests
83− - BENCH=--enable-benchmarks
84− - GHCHEAD=${GHCHEAD-false}
85− - rm -f $CABALHOME/config
86− - |
87− echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config
88− echo "remote-build-reporting: anonymous" >> $CABALHOME/config
89− echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config
90− echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config
91− echo "world-file: $CABALHOME/world" >> $CABALHOME/config
92− echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config
93− echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config
94− echo "installdir: $CABALHOME/bin" >> $CABALHOME/config
95− echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config
96− echo "store-dir: $CABALHOME/store" >> $CABALHOME/config
97− echo "install-dirs user" >> $CABALHOME/config
98− echo " prefix: $CABALHOME" >> $CABALHOME/config
99− echo "repository hackage.haskell.org" >> $CABALHOME/config
100− echo " url: http://hackage.haskell.org/" >> $CABALHOME/config
101− - |
102− if $GHCHEAD; then
103− echo "allow-newer: $($HCPKG list --simple-output | sed -E 's/([a-zA-Z-]+)-[0-9.]+/*:\1/g')" >> $CABALHOME/config
104−
105− echo "repository head.hackage" >> $CABALHOME/config
106− echo " url: http://head.hackage.haskell.org/" >> $CABALHOME/config
107− echo " secure: True" >> $CABALHOME/config
108− echo " root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740" >> $CABALHOME/config
109− echo " 2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb" >> $CABALHOME/config
110− echo " 8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e" >> $CABALHOME/config
111− echo " key-threshold: 3" >> $CABALHOME/config
112− fi
113− - cat $CABALHOME/config
114− - rm -fv cabal.project cabal.project.local cabal.project.freeze
115− - travis_retry ${CABAL} v2-update -v
116− # Generate cabal.project
117− - rm -rf cabal.project cabal.project.local cabal.project.freeze
118− - touch cabal.project
119− - |
120− echo 'packages: "."' >> cabal.project
121− - |
122− echo "write-ghc-environment-files: always" >> cabal.project
123− - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(http-api-data)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
124− - cat cabal.project || true
125− - cat cabal.project.local || true
126− - if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi
127− - ${CABAL} v2-freeze -w ${HC} ${TEST} ${BENCH} | color_cabal_output
128− - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
129− - rm cabal.project.freeze
130− - ${CABAL} v2-build -w ${HC} ${TEST} ${BENCH} --dep -j2 all | color_cabal_output
131− - ${CABAL} v2-build -w ${HC} --disable-tests --disable-benchmarks --dep -j2 all | color_cabal_output
132−script:
133− - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
134− # Packaging...
135− - ${CABAL} v2-sdist all | color_cabal_output
136− # Unpacking...
137− - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
138− - cd ${DISTDIR} || false
139− - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
140− # Generate cabal.project
141− - rm -rf cabal.project cabal.project.local cabal.project.freeze
142− - touch cabal.project
143− - |
144− echo 'packages: "http-api-data-*/*.cabal"' >> cabal.project
145− - |
146− echo "write-ghc-environment-files: always" >> cabal.project
147− - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(http-api-data)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
148− - cat cabal.project || true
149− - cat cabal.project.local || true
150− # Building...
151− # this builds all libraries and executables (without tests/benchmarks)
152− - ${CABAL} v2-build -w ${HC} --disable-tests --disable-benchmarks all | color_cabal_output
153− # Building with tests and benchmarks...
154− # build & run tests, build benchmarks
155− - ${CABAL} v2-build -w ${HC} ${TEST} ${BENCH} all | color_cabal_output
156− # Testing...
157− - ${CABAL} v2-test -w ${HC} ${TEST} ${BENCH} all | color_cabal_output
158− # cabal check...
159− - (cd http-api-data-* && ${CABAL} -vnormal check)
160− # haddock...
161− - ${CABAL} v2-haddock -w ${HC} ${TEST} ${BENCH} all | color_cabal_output
162− # Building without installed constraints for packages in global-db...
163− - rm -f cabal.project.local
164− - ${CABAL} v2-build -w ${HC} --disable-tests --disable-benchmarks all | color_cabal_output
165− # Constraint sets
166− - rm -rf cabal.project.local
167− # Constraint set text-show
168− - ${CABAL} v2-build -w ${HC} --disable-tests --disable-benchmarks --constraint='http-api-data +use-text-show' all | color_cabal_output
169−
170−# REGENDATA ["--config=cabal.haskell-ci","http-api-data.cabal"]
171−# EOF
CHANGELOG.md+24
@@ -1,3 +1,27 @@
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+
14+0.4.2
15+-----
16+
17+* Add instances for `Const` and `Identity`
18+
19+0.4.1.1
20+-------
21+
22+* Allow cookie <0.5
23+* Change to `build-type: Simple`
24+
10.4.1
250.4.1
2-----
26-----
3
27
Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
Setup.lhsdeleted−36
@@ -1,36 +0,0 @@
1−\begin{code}
2−{-# LANGUAGE CPP #-}
3−{-# OPTIONS_GHC -Wall #-}
4−module Main (main) where
5−
6−#ifndef MIN_VERSION_cabal_doctest
7−#define MIN_VERSION_cabal_doctest(x,y,z) 0
8−#endif
9−
10−#if MIN_VERSION_cabal_doctest(1,0,0)
11−
12−import Distribution.Extra.Doctest ( defaultMainWithDoctests )
13−main :: IO ()
14−main = defaultMainWithDoctests "doctests"
15−
16−#else
17−
18−#ifdef MIN_VERSION_Cabal
19−-- If the macro is defined, we have new cabal-install,
20−-- but for some reason we don't have cabal-doctest in package-db
21−--
22−-- Probably we are running cabal sdist, when otherwise using new-build
23−-- workflow
24−#warning You are configuring this package without cabal-doctest installed. \
25− The doctests test-suite will not work as a result. \
26− To fix this, install cabal-doctest before configuring.
27−#endif
28−
29−import Distribution.Simple
30−
31−main :: IO ()
32−main = defaultMain
33−
34−#endif
35−
36−\end{code}
cabal.haskell-ci+2
@@ -1,4 +1,6 @@
1branches: master
1branches: master
2+doctest: <9
3+doctest-filter-packages: base-compat
2
4
3constraint-set text-show
5constraint-set text-show
4 constraints: http-api-data +use-text-show
6 constraints: http-api-data +use-text-show
cabal.project+1−1
@@ -1,2 +1,2 @@
1packages: .
1packages: .
2−tests: true
2+tests: True
http-api-data.cabal+28−53
@@ -1,6 +1,6 @@
1cabal-version: >= 1.10
1cabal-version: >= 1.10
2name: http-api-data
2name: http-api-data
3−version: 0.4.1
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
@@ -15,7 +15,7 @@ author: Nickolay Kudasov <nickolay.kudasov@gmail.com>
15maintainer: Nickolay Kudasov <nickolay.kudasov@gmail.com>
15maintainer: Nickolay Kudasov <nickolay.kudasov@gmail.com>
16homepage: http://github.com/fizruk/http-api-data
16homepage: http://github.com/fizruk/http-api-data
17stability: unstable
17stability: unstable
18−build-type: Custom
18+build-type: Simple
19
19
20extra-source-files:
20extra-source-files:
21 include/overlapping-compat.h
21 include/overlapping-compat.h
@@ -24,19 +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.1
31+ GHC==8.8.4,
34−
32+ GHC==8.10.7,
35−custom-setup
33+ GHC==9.0.2,
36− setup-depends:
34+ GHC==9.2.3,
37− base,
35+ GHC==9.4.1
38− Cabal,
39− cabal-doctest >=1.0.6 && <1.1
40
36
41flag use-text-show
37flag use-text-show
42 description: Use text-show library for efficient ToHttpApiData implementations.
38 description: Use text-show library for efficient ToHttpApiData implementations.
@@ -48,39 +44,28 @@ library
48 include-dirs: include/
44 include-dirs: include/
49
45
50 -- GHC bundled
46 -- GHC bundled
51− build-depends: base >= 4.7 && < 4.13
47+ build-depends: base >= 4.9 && < 4.17
52− , bytestring >= 0.10.4.0 && < 0.11
48+ , bytestring >= 0.10.8.1 && < 0.12
53− , containers >= 0.5.5.1 && < 0.7
49+ , containers >= 0.5.7.1 && < 0.7
54− , text >= 1.2.3.0 && < 1.3
50+ , text >= 1.2.3.0 && < 1.3 || >=2.0 && <2.1
55−
51+ , transformers >= 0.5.2.0 && < 0.7
56− -- so Semigroup Builder exists
57− if impl(ghc >= 8.0)
58− build-depends: bytestring >= 0.10.8.1
59
52
60 -- other-dependencies
53 -- other-dependencies
61 build-depends:
54 build-depends:
62− attoparsec >= 0.13.2.2 && < 0.14
55+ attoparsec >= 0.13.2.2 && < 0.15
63− , attoparsec-iso8601 >= 1.0.1.0 && < 1.1
56+ , attoparsec-iso8601 >= 1.1.0.0 && < 1.2
64− , base-compat >= 0.10.5 && < 0.11
57+ , base-compat >= 0.10.5 && < 0.13
65− , cookie >= 0.4.3 && < 0.4.5
58+ , cookie >= 0.4.3 && < 0.5
66− , hashable >= 1.2.7.0 && < 1.4
59+ , hashable >= 1.2.7.0 && < 1.5
67 , http-types >= 0.12.3 && < 0.13
60 , http-types >= 0.12.3 && < 0.13
68 , tagged >= 0.8.5 && < 0.9
61 , tagged >= 0.8.5 && < 0.9
69− , time-compat >= 1.9.2 && < 1.10
62+ , time-compat >= 1.9.5 && < 1.10
70− , unordered-containers >= 0.2.10.0 && < 0.3
63+ , unordered-containers >= 0.2.10.0 && < 0.3
71− , uuid-types >= 1.0.3 && <1.1
64+ , uuid-types >= 1.0.3 && < 1.1
72−
73− if !impl(ghc >= 7.10)
74− build-depends:
75− nats >= 1.1.2 && < 1.2,
76− void >= 0.7.3 && < 0.8
77−
78− if !impl(ghc >= 8.0)
79− build-depends: semigroups >= 0.18.5 && < 0.20
80
65
81 if flag(use-text-show)
66 if flag(use-text-show)
82 cpp-options: -DUSE_TEXT_SHOW
67 cpp-options: -DUSE_TEXT_SHOW
83− build-depends: text-show >= 3.8.2 && <3.9
68+ build-depends: text-show >= 3.8.2 && <3.10
84
69
85 exposed-modules:
70 exposed-modules:
86 Web.HttpApiData
71 Web.HttpApiData
@@ -100,7 +85,7 @@ test-suite spec
100 hs-source-dirs: test
85 hs-source-dirs: test
101 ghc-options: -Wall
86 ghc-options: -Wall
102 default-language: Haskell2010
87 default-language: Haskell2010
103− 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
104 -- inherited depndencies
89 -- inherited depndencies
105 build-depends:
90 build-depends:
106 base
91 base
@@ -108,28 +93,18 @@ test-suite spec
108 , bytestring
93 , bytestring
109 , cookie
94 , cookie
110 , http-api-data
95 , http-api-data
111− , nats
112 , text
96 , text
113 , time-compat
97 , time-compat
114 , unordered-containers
98 , unordered-containers
115 , uuid-types
99 , uuid-types
116
100
101+ if !impl(ghc >= 7.10)
117− build-depends: HUnit >= 1.6.0.0 && <1.7
102+ build-depends: nats
118− , hspec >= 2.7.1 && <2.8
119− , QuickCheck >= 2.13.1 && <2.14
120− , quickcheck-instances >= 0.3.21 && <0.4
121
103
122−test-suite doctests
123− ghc-options: -Wall
124− build-depends:
104+ build-depends: HUnit >= 1.6.0.0 && <1.7
125− base,
105+ , hspec >= 2.7.1 && <2.11
126− directory >= 1.0,
106+ , QuickCheck >= 2.13.1 && <2.15
127− doctest >= 0.16.0 && <0.17,
107+ , quickcheck-instances >= 0.3.25.2 && <0.4
128− filepath
129− default-language: Haskell2010
130− hs-source-dirs: test
131− main-is: doctests.hs
132− type: exitcode-stdio-1.0
133
108
134source-repository head
109source-repository head
135 type: git
110 type: git
src/Web/Internal/FormUrlEncoded.hs+25−1
@@ -1,5 +1,5 @@
1−{-# LANGUAGE CPP #-}
2{-# LANGUAGE ConstraintKinds #-}
1{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE CPP #-}
3{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE DataKinds #-}
4{-# LANGUAGE DefaultSignatures #-}
4{-# LANGUAGE DefaultSignatures #-}
5{-# LANGUAGE DeriveGeneric #-}
5{-# LANGUAGE DeriveGeneric #-}
@@ -20,6 +20,7 @@ module Web.Internal.FormUrlEncoded where
20import Prelude ()
20import Prelude ()
21import Prelude.Compat
21import Prelude.Compat
22
22
23+import Control.Applicative (Const(Const))
23import Control.Arrow ((***))
24import Control.Arrow ((***))
24import Control.Monad ((<=<))
25import Control.Monad ((<=<))
25import Data.ByteString.Builder (shortByteString, toLazyByteString)
26import Data.ByteString.Builder (shortByteString, toLazyByteString)
@@ -27,6 +28,7 @@ import qualified Data.ByteString.Lazy as BSL
27import qualified Data.ByteString.Lazy.Char8 as BSL8
28import qualified Data.ByteString.Lazy.Char8 as BSL8
28import Data.Coerce (coerce)
29import Data.Coerce (coerce)
29import qualified Data.Foldable as F
30import qualified Data.Foldable as F
31+import Data.Functor.Identity (Identity(Identity))
30import Data.Hashable (Hashable)
32import Data.Hashable (Hashable)
31import Data.HashMap.Strict (HashMap)
33import Data.HashMap.Strict (HashMap)
32import qualified Data.HashMap.Strict as HashMap
34import qualified Data.HashMap.Strict as HashMap
@@ -50,6 +52,8 @@ import Data.Text.Encoding.Error (lenientDecode)
50import qualified Data.Text.Lazy as Lazy
52import qualified Data.Text.Lazy as Lazy
51import Data.Time.Compat (Day, LocalTime, NominalDiffTime,
53import Data.Time.Compat (Day, LocalTime, NominalDiffTime,
52 UTCTime, ZonedTime)
54 UTCTime, ZonedTime)
55+import Data.Time.Calendar.Month.Compat (Month)
56+import Data.Time.Calendar.Quarter.Compat (Quarter, QuarterOfYear (..))
53import Data.Void (Void)
57import Data.Void (Void)
54import Data.Word (Word16, Word32, Word64, Word8)
58import Data.Word (Word16, Word32, Word64, Word8)
55import GHC.Exts (Constraint, IsList (..))
59import GHC.Exts (Constraint, IsList (..))
@@ -111,6 +115,9 @@ instance ToFormKey LocalTime where toFormKey = toQueryParam
111instance ToFormKey ZonedTime where toFormKey = toQueryParam
115instance ToFormKey ZonedTime where toFormKey = toQueryParam
112instance ToFormKey UTCTime where toFormKey = toQueryParam
116instance ToFormKey UTCTime where toFormKey = toQueryParam
113instance 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
114
121
115instance ToFormKey String where toFormKey = toQueryParam
122instance ToFormKey String where toFormKey = toQueryParam
116instance ToFormKey Text where toFormKey = toQueryParam
123instance ToFormKey Text where toFormKey = toQueryParam
@@ -130,6 +137,13 @@ instance ToFormKey a => ToFormKey (Semi.Last a) where toFormKey = coerce (toFor
130
137
131instance ToFormKey a => ToFormKey (Tagged b a) where toFormKey = coerce (toFormKey :: a -> Text)
138instance ToFormKey a => ToFormKey (Tagged b a) where toFormKey = coerce (toFormKey :: a -> Text)
132
139
140+-- | @since 0.4.2
141+instance ToFormKey a => ToFormKey (Identity a) where toFormKey = coerce (toFormKey :: a -> Text)
142+
143+-- | @since 0.4.2
144+instance ToFormKey a => ToFormKey (Const a b) where
145+ toFormKey = coerce (toFormKey :: a -> Text)
146+
133instance ToFormKey Void where toFormKey = toQueryParam
147instance ToFormKey Void where toFormKey = toQueryParam
134instance ToFormKey Natural where toFormKey = toQueryParam
148instance ToFormKey Natural where toFormKey = toQueryParam
135
149
@@ -163,6 +177,9 @@ instance FromFormKey LocalTime where parseFormKey = parseQueryParam
163instance FromFormKey ZonedTime where parseFormKey = parseQueryParam
177instance FromFormKey ZonedTime where parseFormKey = parseQueryParam
164instance FromFormKey UTCTime where parseFormKey = parseQueryParam
178instance FromFormKey UTCTime where parseFormKey = parseQueryParam
165instance 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
166
183
167instance FromFormKey String where parseFormKey = parseQueryParam
184instance FromFormKey String where parseFormKey = parseQueryParam
168instance FromFormKey Text where parseFormKey = parseQueryParam
185instance FromFormKey Text where parseFormKey = parseQueryParam
@@ -182,6 +199,13 @@ instance FromFormKey a => FromFormKey (Semi.Last a) where parseFormKey = coerce
182
199
183instance FromFormKey a => FromFormKey (Tagged b a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
200instance FromFormKey a => FromFormKey (Tagged b a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
184
201
202+-- | @since 0.4.2
203+instance FromFormKey a => FromFormKey (Identity a) where parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
204+
205+-- | @since 0.4.2
206+instance FromFormKey a => FromFormKey (Const a b) where
207+ parseFormKey = coerce (parseFormKey :: Text -> Either Text a)
208+
185instance FromFormKey Void where parseFormKey = parseQueryParam
209instance FromFormKey Void where parseFormKey = parseQueryParam
186instance FromFormKey Natural where parseFormKey = parseQueryParam
210instance FromFormKey Natural where parseFormKey = parseQueryParam
187
211
src/Web/Internal/HttpApiData.hs+107−12
@@ -5,7 +5,9 @@
5{-# LANGUAGE DeriveFunctor #-}
5{-# LANGUAGE DeriveFunctor #-}
6{-# LANGUAGE DeriveTraversable #-}
6{-# LANGUAGE DeriveTraversable #-}
7{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE FlexibleInstances #-}
8+{-# LANGUAGE KindSignatures #-}
8{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE OverloadedStrings #-}
10+{-# LANGUAGE PolyKinds #-}
9{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE TypeSynonymInstances #-}
12{-# LANGUAGE TypeSynonymInstances #-}
11-- |
13-- |
@@ -16,6 +18,7 @@ module Web.Internal.HttpApiData where
16import Prelude ()
18import Prelude ()
17import Prelude.Compat
19import Prelude.Compat
18
20
21+import Control.Applicative (Const(Const))
19import Control.Arrow (left, (&&&))
22import Control.Arrow (left, (&&&))
20import Control.Monad ((<=<))
23import Control.Monad ((<=<))
21import qualified Data.Attoparsec.Text as Atto
24import qualified Data.Attoparsec.Text as Atto
@@ -27,7 +30,9 @@ import qualified Data.ByteString.Lazy as LBS
27import Data.Coerce (coerce)
30import Data.Coerce (coerce)
28import Data.Data (Data)
31import Data.Data (Data)
29import qualified Data.Fixed as F
32import qualified Data.Fixed as F
33+import Data.Functor.Identity (Identity(Identity))
30import Data.Int (Int16, Int32, Int64, Int8)
34import Data.Int (Int16, Int32, Int64, Int8)
35+import Data.Kind (Type)
31import qualified Data.Map as Map
36import qualified Data.Map as Map
32import Data.Monoid (All (..), Any (..), Dual (..),
37import Data.Monoid (All (..), Any (..), Dual (..),
33 First (..), Last (..),
38 First (..), Last (..),
@@ -51,6 +56,9 @@ import Data.Time.Compat (Day, FormatTime, LocalTime,
51 secondsToNominalDiffTime)
56 secondsToNominalDiffTime)
52import Data.Time.Format.Compat (defaultTimeLocale,
57import Data.Time.Format.Compat (defaultTimeLocale,
53 iso8601DateFormat)
58 iso8601DateFormat)
59+import Data.Time.Calendar.Month.Compat (Month)
60+import Data.Time.Calendar.Quarter.Compat (Quarter, QuarterOfYear (..),
61+ toYearQuarter)
54import Data.Typeable (Typeable)
62import Data.Typeable (Typeable)
55import qualified Data.UUID.Types as UUID
63import qualified Data.UUID.Types as UUID
56import Data.Version (Version, parseVersion,
64import Data.Version (Version, parseVersion,
@@ -64,14 +72,10 @@ import Text.Read (readMaybe)
64import Web.Cookie (SetCookie, parseSetCookie,
72import Web.Cookie (SetCookie, parseSetCookie,
65 renderSetCookie)
73 renderSetCookie)
66
74
67−
68#if USE_TEXT_SHOW
75#if USE_TEXT_SHOW
69import TextShow (TextShow, showt)
76import TextShow (TextShow, showt)
70#endif
77#endif
71
78
72−
73−
74−
75-- $setup
79-- $setup
76-- >>> data BasicAuthToken = BasicAuthToken Text deriving (Show)
80-- >>> data BasicAuthToken = BasicAuthToken Text deriving (Show)
77-- >>> instance FromHttpApiData BasicAuthToken where parseHeader h = BasicAuthToken <$> parseHeaderWithPrefix "Basic " h; parseQueryParam p = BasicAuthToken <$> parseQueryParam p
81-- >>> instance FromHttpApiData BasicAuthToken where parseHeader h = BasicAuthToken <$> parseHeaderWithPrefix "Basic " h; parseQueryParam p = BasicAuthToken <$> parseQueryParam p
@@ -92,7 +96,7 @@ class ToHttpApiData a where
92 -- The default definition uses 'H.encodePathSegmentsRelative',
96 -- The default definition uses 'H.encodePathSegmentsRelative',
93 -- but this may be overriden with a more efficient version.
97 -- but this may be overriden with a more efficient version.
94 toEncodedUrlPiece :: a -> BS.Builder
98 toEncodedUrlPiece :: a -> BS.Builder
95− toEncodedUrlPiece = H.encodePathSegmentsRelative . (:[]) . toUrlPiece
99+ toEncodedUrlPiece = H.urlEncodeBuilder True . encodeUtf8 . toUrlPiece
96
100
97 -- | Convert to HTTP header value.
101 -- | Convert to HTTP header value.
98 toHeader :: a -> ByteString
102 toHeader :: a -> ByteString
@@ -334,7 +338,7 @@ lookupBoundedEnumOf f = flip lookup (map (f &&& id) [minBound..maxBound])
334-- >>> parseBoundedEnumOf toUrlPiece "true" :: Either Text Bool
338-- >>> parseBoundedEnumOf toUrlPiece "true" :: Either Text Bool
335-- Right True
339-- Right True
336--
340--
337−-- For case sensitive parser see 'parseBoundedEnumOfI'.
341+-- For case insensitive parser see 'parseBoundedEnumOfI'.
338parseBoundedEnumOf :: (Bounded a, Enum a) => (a -> Text) -> Text -> Either Text a
342parseBoundedEnumOf :: (Bounded a, Enum a) => (a -> Text) -> Text -> Either Text a
339parseBoundedEnumOf = parseMaybeTextData . lookupBoundedEnumOf
343parseBoundedEnumOf = parseMaybeTextData . lookupBoundedEnumOf
340
344
@@ -455,7 +459,8 @@ instance ToHttpApiData Word16 where toUrlPiece = showt; toEncodedUrlPiece = un
455instance ToHttpApiData Word32 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
459instance ToHttpApiData Word32 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
456instance ToHttpApiData Word64 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
460instance ToHttpApiData Word64 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
457
461
462+-- | Note: this instance is not polykinded
458−instance F.HasResolution a => ToHttpApiData (F.Fixed a) where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
463+instance F.HasResolution a => ToHttpApiData (F.Fixed (a :: Type)) where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
459
464
460-- |
465-- |
461-- >>> toUrlPiece (fromGregorian 2015 10 03)
466-- >>> toUrlPiece (fromGregorian 2015 10 03)
@@ -509,6 +514,42 @@ instance ToHttpApiData DayOfWeek where
509
514
510 toEncodedUrlPiece = unsafeToEncodedUrlPiece
515 toEncodedUrlPiece = unsafeToEncodedUrlPiece
511
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"
512
553
513instance ToHttpApiData NominalDiffTime where
554instance ToHttpApiData NominalDiffTime where
514 toUrlPiece = toUrlPiece . nominalDiffTimeToSeconds
555 toUrlPiece = toUrlPiece . nominalDiffTimeToSeconds
@@ -592,7 +633,22 @@ instance ToHttpApiData SetCookie where
592 toHeader = LBS.toStrict . BS.toLazyByteString . renderSetCookie
633 toHeader = LBS.toStrict . BS.toLazyByteString . renderSetCookie
593 -- toEncodedUrlPiece = renderSetCookie -- doesn't do things.
634 -- toEncodedUrlPiece = renderSetCookie -- doesn't do things.
594
635
636+-- | Note: this instance is not polykinded
595−instance ToHttpApiData a => ToHttpApiData (Tagged b a) where
637+instance ToHttpApiData a => ToHttpApiData (Tagged (b :: Type) a) where
638+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
639+ toHeader = coerce (toHeader :: a -> ByteString)
640+ toQueryParam = coerce (toQueryParam :: a -> Text)
641+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
642+
643+-- | @since 0.4.2
644+instance ToHttpApiData a => ToHttpApiData (Const a b) where
645+ toUrlPiece = coerce (toUrlPiece :: a -> Text)
646+ toHeader = coerce (toHeader :: a -> ByteString)
647+ toQueryParam = coerce (toQueryParam :: a -> Text)
648+ toEncodedUrlPiece = coerce (toEncodedUrlPiece :: a -> BS.Builder)
649+
650+-- | @since 0.4.2
651+instance ToHttpApiData a => ToHttpApiData (Identity a) where
596 toUrlPiece = coerce (toUrlPiece :: a -> Text)
652 toUrlPiece = coerce (toUrlPiece :: a -> Text)
597 toHeader = coerce (toHeader :: a -> ByteString)
653 toHeader = coerce (toHeader :: a -> ByteString)
598 toQueryParam = coerce (toQueryParam :: a -> Text)
654 toQueryParam = coerce (toQueryParam :: a -> Text)
@@ -650,7 +706,8 @@ instance FromHttpApiData String where parseUrlPiece = Right . T.unpack
650instance FromHttpApiData Text where parseUrlPiece = Right
706instance FromHttpApiData Text where parseUrlPiece = Right
651instance FromHttpApiData L.Text where parseUrlPiece = Right . L.fromStrict
707instance FromHttpApiData L.Text where parseUrlPiece = Right . L.fromStrict
652
708
709+-- | Note: this instance is not polykinded
653−instance F.HasResolution a => FromHttpApiData (F.Fixed a) where
710+instance F.HasResolution a => FromHttpApiData (F.Fixed (a :: Type)) where
654 parseUrlPiece = runReader rational
711 parseUrlPiece = runReader rational
655
712
656-- |
713-- |
@@ -681,6 +738,9 @@ instance FromHttpApiData ZonedTime where parseUrlPiece = runAtto Atto.zonedTime
681-- Right 2015-10-03 00:14:24 UTC
738-- Right 2015-10-03 00:14:24 UTC
682instance FromHttpApiData UTCTime where parseUrlPiece = runAtto Atto.utcTime
739instance FromHttpApiData UTCTime where parseUrlPiece = runAtto Atto.utcTime
683
740
741+-- |
742+-- >>> parseUrlPiece "Monday" :: Either Text DayOfWeek
743+-- Right Monday
684instance FromHttpApiData DayOfWeek where
744instance FromHttpApiData DayOfWeek where
685 parseUrlPiece t = case Map.lookup (T.toLower t) m of
745 parseUrlPiece t = case Map.lookup (T.toLower t) m of
686 Just dow -> Right dow
746 Just dow -> Right dow
@@ -692,6 +752,30 @@ instance FromHttpApiData DayOfWeek where
692
752
693instance FromHttpApiData NominalDiffTime where parseUrlPiece = fmap secondsToNominalDiffTime . parseUrlPiece
753instance FromHttpApiData NominalDiffTime where parseUrlPiece = fmap secondsToNominalDiffTime . parseUrlPiece
694
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+
695instance FromHttpApiData All where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
779instance FromHttpApiData All where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
696instance FromHttpApiData Any where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
780instance FromHttpApiData Any where parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text Bool)
697
781
@@ -755,7 +839,20 @@ instance FromHttpApiData SetCookie where
755 parseUrlPiece = parseHeader . encodeUtf8
839 parseUrlPiece = parseHeader . encodeUtf8
756 parseHeader = Right . parseSetCookie
840 parseHeader = Right . parseSetCookie
757
841
842+-- | Note: this instance is not polykinded
758−instance FromHttpApiData a => FromHttpApiData (Tagged b a) where
843+instance FromHttpApiData a => FromHttpApiData (Tagged (b :: Type) a) where
844+ parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
845+ parseHeader = coerce (parseHeader :: ByteString -> Either Text a)
846+ parseQueryParam = coerce (parseQueryParam :: Text -> Either Text a)
847+
848+-- | @since 0.4.2
849+instance FromHttpApiData a => FromHttpApiData (Const a b) where
850+ parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
851+ parseHeader = coerce (parseHeader :: ByteString -> Either Text a)
852+ parseQueryParam = coerce (parseQueryParam :: Text -> Either Text a)
853+
854+-- | @since 0.4.2
855+instance FromHttpApiData a => FromHttpApiData (Identity a) where
759 parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
856 parseUrlPiece = coerce (parseUrlPiece :: Text -> Either Text a)
760 parseHeader = coerce (parseHeader :: ByteString -> Either Text a)
857 parseHeader = coerce (parseHeader :: ByteString -> Either Text a)
761 parseQueryParam = coerce (parseQueryParam :: Text -> Either Text a)
858 parseQueryParam = coerce (parseQueryParam :: Text -> Either Text a)
@@ -768,5 +865,3 @@ runAtto :: Atto.Parser a -> Text -> Either Text a
768runAtto p t = case Atto.parseOnly (p <* Atto.endOfInput) t of
865runAtto p t = case Atto.parseOnly (p <* Atto.endOfInput) t of
769 Left err -> Left (T.pack err)
866 Left err -> Left (T.pack err)
770 Right x -> Right x
867 Right x -> Right x
771−
772−
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"
test/doctests.hsdeleted−25
@@ -1,25 +0,0 @@
1−-----------------------------------------------------------------------------
2−-- |
3−-- Module : Main (doctests)
4−-- Copyright : (C) 2012-14 Edward Kmett
5−-- License : BSD-style (see the file LICENSE)
6−-- Maintainer : Edward Kmett <ekmett@gmail.com>
7−-- Stability : provisional
8−-- Portability : portable
9−--
10−-- This module provides doctests for a project based on the actual versions
11−-- of the packages it was built with. It requires a corresponding Setup.lhs
12−-- to be added to the project
13−-----------------------------------------------------------------------------
14−module Main where
15−
16−import Build_doctests (flags, pkgs, module_sources)
17−import Data.Foldable (traverse_)
18−import Test.DocTest
19−
20−main :: IO ()
21−main = do
22− traverse_ putStrLn args
23− doctest args
24− where
25− args = flags ++ pkgs ++ module_sources