on dd8025e help sign in
.github/actions/common_setup/action.yaml+9−27
since splitsnapshots
unifiedsplit
@@ -1,34 +1,15 @@
1name: "Common setup"
1name: "Common setup"
2description: "Common setup steps"
2description: "Common setup steps"
3inputs:
3inputs:
4− authToken:
4+ key:
5− description: "Cachix auth token"
5+ description: "Caching key"
6 required: true
6 required: true
7+ restore-keys:
8+ description: "Restore keys"
9+ required: false
7runs:
10runs:
8 using: "composite"
11 using: "composite"
9 steps:
12 steps:
10− - name: Increase swap if linux
11− shell: bash
12− run: |
13− if [ "$RUNNER_OS" == "Linux" ]; then
14−
15− echo "Is Linux"
16−
17− free -h
18−
19− sudo swapoff /mnt/swapfile
20− sudo fallocate -l 12G /mnt/swapfile
21− sudo mkswap /mnt/swapfile
22− sudo swapon /mnt/swapfile
23−
24− free -h
25−
26− else
27−
28− echo "Not Linux"
29−
30− fi
31−
32 - name: Install Nix
13 - name: Install Nix
33 uses: cachix/install-nix-action@v16
14 uses: cachix/install-nix-action@v16
34 with:
15 with:
@@ -36,7 +17,8 @@ runs:
36 system-features = kvm
17 system-features = kvm
37 trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
18 trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
38 substituters = https://hydra.iohk.io https://cache.nixos.org/
19 substituters = https://hydra.iohk.io https://cache.nixos.org/
39− - uses: cachix/cachix-action@v10
20+ - name: Cache Nix
21+ uses: ./.github/actions/nix_cache
40 with:
22 with:
41− name: typeable
23+ key: ${{ inputs.key }}
42− authToken: "${{ inputs.authToken }}"
24+ restore-keys: ${{ inputs.restore-keys }}
.github/actions/nix_cache/action.yamlnew file+47
@@ -0,0 +1,47 @@
1+name: "Nix cache"
2+description: "Cache nix build"
3+inputs:
4+ key:
5+ description: "Caching key"
6+ required: true
7+ restore-keys:
8+ description: "Restore keys"
9+ required: false
10+ default: ""
11+runs:
12+ using: "composite"
13+ steps:
14+ # - name: Install Nix
15+ # uses: cachix/install-nix-action@v16
16+ # with:
17+ # extra_nix_config: |
18+ # system-features = kvm
19+ # trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
20+ # substituters = https://hydra.iohk.io https://cache.nixos.org/
21+ - name: Install Nix
22+ uses: cachix/install-nix-action@v16
23+ with:
24+ extra_nix_config: |
25+ system-features = kvm
26+ trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
27+ substituters = https://hydra.iohk.io https://cache.nixos.org/
28+ - name: Cache Nix
29+ id: cache-nix
30+ uses: actions/cache@v2.1.7
31+ with:
32+ path: |
33+ ~/nix/store/
34+ ~/nix/var/nix/db/db.sqlite
35+ key: ${{ inputs.key }}
36+ restore-keys: ${{ inputs.restore-keys }}
37+ - name: make nix store writable
38+ shell: bash
39+ run: |
40+ ls ~
41+ echo
42+ if [[ -d ~/nix ]]; then
43+ echo "in"
44+ ls ~/nix
45+ find ~/nix/store -maxdepth 1 | sudo xargs -I {} mv -f {} /nix/store/
46+ sudo mv -f ~/nix/var/nix/db/db.sqlite /nix/var/nix/db/db.sqlite
47+ fi
.github/actions/nix_cache_post/action.yamlnew file+11
@@ -0,0 +1,11 @@
1+name: "Nix cache post"
2+description: "Cache nix build post"
3+runs:
4+ using: "composite"
5+ steps:
6+ - name: Move nix store
7+ shell: bash
8+ run: |
9+ mkdir -p ~/nix/store/ ~/nix/var/nix/db/
10+ find /nix/store -maxdepth 1 | sudo xargs -I {} mv -f {} ~/nix/store/
11+ sudo mv -f /nix/var/nix/db/db.sqlite ~/nix/var/nix/db/db.sqlite
.github/workflows/github-actions-image.yaml+66−172
@@ -9,81 +9,21 @@ on:
9 types: [prereleased]
9 types: [prereleased]
10
10
11jobs:
11jobs:
12− check-formatting:
12+ Linux:
13− name: Check Haskell formatting
14− runs-on: ubuntu-latest
15− steps:
16− - uses: actions/checkout@v2
17−
18− - name: Common setup
19− uses: ./.github/actions/common_setup
20− with:
21− authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
22−
23− - name: Run fourmolu
24− run: |
25− nix-shell nix/ci.nix -j auto --run "git ls-files '*.hs' | xargs fourmolu -m inplace -o -XRecursiveDo -o -XTypeApplications -o -XPatternSynonyms -o -XBangPatterns"
26− git diff --exit-code
27−
28− policeman:
29− runs-on: ubuntu-latest
30− steps:
31− - uses: actions/checkout@v2
32− with:
33− submodules: recursive
34−
35− - name: Common setup
36− uses: ./.github/actions/common_setup
37− with:
38− authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
39−
40− - name: Run policeman
41− run: |
42− jq --argjson msg "$( $(nix-build ci/policeman.nix)/bin/policeman | grep -v "⚙" | jq -aRs . )" ".[0].message = \$msg" <policeman.json >message.json
43− cat message.json
44−
45− - name: Post notice
46− uses: yuzutech/annotations-action@v0.4.0
47− with:
48− title: 👮 Policeman
49− repo-token: "${{ secrets.GITHUB_TOKEN }}"
50− input: "./message.json"
51−
52− check_versions:
53 runs-on: ubuntu-latest
13 runs-on: ubuntu-latest
54 steps:
14 steps:
55− - uses: actions/checkout@v2
15+ - name: Increase swap
56− with:
16+ shell: bash
57− submodules: recursive
58−
59− - name: Check library version
60− if: github.event_name == 'release'
61 run: |
17 run: |
62− if [ "$(awk -F ':' '/^version/ {gsub(/ /, "", $2); print $2}' compaREST.cabal)" != "${{ github.event.release.tag_name }}" ]; then
18+ free -h
63− echo "::error file=compaREST.cabal::Library version does not match release version."
64− exit 1
65− fi
66
19
67− - name: Check docker tag
20+ sudo swapoff /mnt/swapfile
68− if: github.event_name == 'release'
21+ sudo fallocate -l 12G /mnt/swapfile
69− run: |
22+ sudo mkswap /mnt/swapfile
70− if [ "$(yq eval '.runs.image' action.yaml | awk -F ':' '{print $NF}')" != "${{ github.event.release.tag_name }}" ]; then
23+ sudo swapon /mnt/swapfile
71− echo "::error file=action.yaml::Action docker tag does not match release tag."
72− exit 1
73− fi
74
24
75− - name: Check changelog
25+ free -h
76− if: github.event_name == 'release'
77− run: |
78− if ! grep '^## ${{ github.event.release.tag_name }}$' CHANGELOG.md; then
79− echo "::error file=CHANGELOG.md::CHANGELOG.md does not contain an entry for this release."
80− exit 1
81− fi
82
26
83− Linux:
84− needs: check_versions
85− runs-on: ubuntu-latest
86− steps:
87 - uses: actions/checkout@v2
27 - uses: actions/checkout@v2
88 with:
28 with:
89 submodules: recursive
29 submodules: recursive
@@ -91,17 +31,15 @@ jobs:
91 - name: Common setup
31 - name: Common setup
92 uses: ./.github/actions/common_setup
32 uses: ./.github/actions/common_setup
93 with:
33 with:
94− authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
34+ key: Linux-${{ hashFiles('**.nix') }}-${{ hashFiles('stack.yaml') }}-${{ hashFiles('**.cabal') }}
95−
35+ restore-keys: |
96− - name: Test
36+ Linux-${{ hashFiles('**.nix') }}-${{ hashFiles('stack.yaml') }}
97− shell: bash
37+ Linux-${{ hashFiles('**.nix') }}
98− run: |
38+ Linux
99− $(nix-build -A test -j auto --no-out-link)/bin/compaREST-tests
100−
101 - name: Build Linux static binary
39 - name: Build Linux static binary
102 shell: bash
40 shell: bash
103 run: |
41 run: |
104− cp $(nix-build -A compaRESTStaticBin -j auto --no-out-link)/bin/compaREST compaREST
42+ cp $(nix-build -A compaRESTStaticBin -j auto)/bin/compaREST compaREST
105
43
106 - name: Upload compaREST Linux Binary
44 - name: Upload compaREST Linux Binary
107 uses: actions/upload-artifact@v2
45 uses: actions/upload-artifact@v2
@@ -109,19 +47,19 @@ jobs:
109 name: compaREST-Linux
47 name: compaREST-Linux
110 path: compaREST
48 path: compaREST
111
49
112− - name: Build Docker Images
50+ - name: Build Github Action Docker Image
113 shell: bash
51 shell: bash
114 run: |
52 run: |
115− cp $(nix-build -A compaRESTGithubAction -j auto --no-out-link) compaREST-Github-Action-image.tar.gz
53+ cp $(nix-build -A compaRESTGithubAction -j auto) compaREST-Github-Action-image.tar.gz
116− cp $(nix-build -A compaRESTImage -j auto --no-out-link) compaREST-image.tar.gz
54+ cp $(nix-build -A compaRESTImage -j auto) compaREST-image.tar.gz
117
55
118− - name: Upload compaREST Docker Github Action Image
56+ - name: Upload compaREST Github Action Image
119 uses: actions/upload-artifact@v2
57 uses: actions/upload-artifact@v2
120 with:
58 with:
121 name: compaREST Github Action Docker Image
59 name: compaREST Github Action Docker Image
122 path: compaREST-Github-Action-image.tar.gz
60 path: compaREST-Github-Action-image.tar.gz
123
61
124− - name: Upload compaREST Docker Image
62+ - name: Upload compaREST Image
125 uses: actions/upload-artifact@v2
63 uses: actions/upload-artifact@v2
126 with:
64 with:
127 name: compaREST Docker Image
65 name: compaREST Docker Image
@@ -135,30 +73,18 @@ jobs:
135 sudo apt-get -y install skopeo
73 sudo apt-get -y install skopeo
136
74
137 - name: Login to DockerHub
75 - name: Login to DockerHub
76+ if: github.event_name == 'release'
138 uses: docker/login-action@v1.10.0
77 uses: docker/login-action@v1.10.0
139 with:
78 with:
140− username: ${{ secrets.DOCKER_HUB_USERNAME }}
79+ username: ${{ secrets.DOCKERHUB_USERNAME }}
141− password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
80+ password: ${{ secrets.DOCKERHUB_TOKEN }}
142−
143− - name: Push Nightly Docker Images to DockerHub
144− if: github.ref == 'refs/heads/master' && github.event_name == 'push'
145− shell: bash
146− run: |
147− skopeo copy docker-archive:$(nix-build -A compaRESTGithubAction -j auto --no-out-link) docker://ilyakooo0/comparest-github-action:nightly
148− skopeo copy docker-archive:$(nix-build -A compaRESTImage -j auto --no-out-link) docker://ilyakooo0/comparest:nightly
149
81
150− - name: Push Release Docker Images to DockerHub
82+ - name: Push Docker Images to DockerHub
151 if: github.event_name == 'release'
83 if: github.event_name == 'release'
152 shell: bash
84 shell: bash
153 run: |
85 run: |
154− skopeo copy docker-archive:$(nix-build -A compaRESTGithubAction -j auto --no-out-link) docker://ilyakooo0/comparest-github-action:${{ github.event.release.tag_name }}
86+ skopeo copy docker-archive:$(nix-build -A compaRESTGithubAction -j auto) docker://typeable/comparest-github-action:${{ github.event.release.tag_name }}
155− skopeo copy docker-archive:$(nix-build -A compaRESTImage -j auto --no-out-link) docker://ilyakooo0/comparest:${{ github.event.release.tag_name }}
87+ skopeo copy docker-archive:$(nix-build -A compaRESTImage -j auto) docker://typeable/comparest:${{ github.event.release.tag_name }}
156−
157− - name: Zip Release Assets
158− if: github.event_name == 'release'
159− shell: bash
160− run: |
161− zip compaREST-Linux-x86.zip compaREST
162
88
163 - name: Upload compaREST Github Action Docker Image to release
89 - name: Upload compaREST Github Action Docker Image to release
164 if: github.event_name == 'release'
90 if: github.event_name == 'release'
@@ -166,6 +92,7 @@ jobs:
166 with:
92 with:
167 repo_token: ${{ secrets.GITHUB_TOKEN }}
93 repo_token: ${{ secrets.GITHUB_TOKEN }}
168 file: compaREST-Github-Action-image.tar.gz
94 file: compaREST-Github-Action-image.tar.gz
95+ asset_name: compaREST Github Action Docker Image
169 tag: ${{ github.ref }}
96 tag: ${{ github.ref }}
170
97
171 - name: Upload compaREST Docker Image to release
98 - name: Upload compaREST Docker Image to release
@@ -174,6 +101,7 @@ jobs:
174 with:
101 with:
175 repo_token: ${{ secrets.GITHUB_TOKEN }}
102 repo_token: ${{ secrets.GITHUB_TOKEN }}
176 file: compaREST-image.tar.gz
103 file: compaREST-image.tar.gz
104+ asset_name: compaREST Docker Image
177 tag: ${{ github.ref }}
105 tag: ${{ github.ref }}
178
106
179 - name: Upload compaREST binary – Linux – x86 to release
107 - name: Upload compaREST binary – Linux – x86 to release
@@ -181,63 +109,14 @@ jobs:
181 uses: svenstaro/upload-release-action@2.2.1
109 uses: svenstaro/upload-release-action@2.2.1
182 with:
110 with:
183 repo_token: ${{ secrets.GITHUB_TOKEN }}
111 repo_token: ${{ secrets.GITHUB_TOKEN }}
184− file: compaREST-Linux-x86.zip
112+ file: compaREST
185− tag: ${{ github.ref }}
113+ asset_name: compaREST binary – Linux – x86
186−
187− dist:
188− needs: check_versions
189− runs-on: ubuntu-latest
190− steps:
191− - uses: actions/checkout@v2
192− with:
193− submodules: recursive
194−
195− - name: Cache
196− uses: actions/cache@v1
197− with:
198− path: |
199− ~/.stack
200− .stack-work
201− key: ${{ runner.os }}-stack-${{ hashFiles('stack.yaml') }}-${{ hashFiles('**.cabal') }}
202− restore-keys: |
203− ${{ runner.os }}-stack-${{ hashFiles('stack.yaml') }}
204− ${{ runner.os }}-stack
205−
206− - name: Upgrade stack
207− shell: bash
208− # Needed for Hackage token authorization
209− run: stack upgrade --git
210−
211− - name: Build dist
212− run: |
213− stack sdist --pvp-bounds both --test-tarball
214− echo "distPath=$(stack path | awk -F ": " '/dist-dir/ {print $2}')" >> $GITHUB_ENV
215−
216− - name: Upload compaREST sources artifact
217− uses: actions/upload-artifact@v2
218− with:
219− name: compaREST sources
220− path: ${{ env.distPath }}/*.tar.gz
221−
222− - name: Upload compaREST sources to release
223− if: github.event_name == 'release'
224− uses: svenstaro/upload-release-action@2.2.1
225− with:
226− repo_token: ${{ secrets.GITHUB_TOKEN }}
227− file_glob: true
228− file: ${{ env.distPath }}/*.tar.gz
229 tag: ${{ github.ref }}
114 tag: ${{ github.ref }}
230
115
231− - name: Publish compaREST candidate to Hackage
116+ - name: Cahce post
232− shell: bash
117+ uses: ./.github/actions/nix_cache_post
233− if: github.event_name == 'release'
234− env:
235− HACKAGE_KEY: ${{ secrets.HACKAGE_KEY }}
236− run: |
237− stack upload --pvp-bounds both --test-tarball --candidate .
238
118
239 macOS:
119 macOS:
240− needs: check_versions
241 runs-on: macos-latest
120 runs-on: macos-latest
242 steps:
121 steps:
243 - uses: actions/checkout@v2
122 - uses: actions/checkout@v2
@@ -247,11 +126,15 @@ jobs:
247 - name: Common setup
126 - name: Common setup
248 uses: ./.github/actions/common_setup
127 uses: ./.github/actions/common_setup
249 with:
128 with:
250− authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
129+ key: macOS-${{ hashFiles('**.nix') }}-${{ hashFiles('stack.yaml') }}-${{ hashFiles('**.cabal') }}
130+ restore-keys: |
131+ macOS-${{ hashFiles('**.nix') }}-${{ hashFiles('stack.yaml') }}
132+ macOS-${{ hashFiles('**.nix') }}
133+ macOS
251
134
252 - name: Build macOS binary bundle
135 - name: Build macOS binary bundle
253 run: |
136 run: |
254− cp -LR $(nix-build -A macOSCompaRESTBundle -j auto --no-out-link) compaREST
137+ cp -LR $(nix-build -A macOSCompaRESTBundle -j auto) compaREST
255
138
256 - name: Upload macOS compaREST bundle
139 - name: Upload macOS compaREST bundle
257 uses: actions/upload-artifact@v2
140 uses: actions/upload-artifact@v2
@@ -259,24 +142,33 @@ jobs:
259 name: compaREST binary – macOS – x86
142 name: compaREST binary – macOS – x86
260 path: compaREST
143 path: compaREST
261
144
262− - name: Zip Release Assets
263− if: github.event_name == 'release'
264− shell: bash
265− run: |
266− zip -r compaREST-macOS-x86.zip compaREST
267−
268 - name: Upload compaREST binary – macOS – x86 to release
145 - name: Upload compaREST binary – macOS – x86 to release
269 if: github.event_name == 'release'
146 if: github.event_name == 'release'
270 uses: svenstaro/upload-release-action@2.2.1
147 uses: svenstaro/upload-release-action@2.2.1
271 with:
148 with:
272 repo_token: ${{ secrets.GITHUB_TOKEN }}
149 repo_token: ${{ secrets.GITHUB_TOKEN }}
273− file: compaREST-macOS-x86.zip
150+ file: compaREST
151+ asset_name: compaREST binary – macOS – x86
274 tag: ${{ github.ref }}
152 tag: ${{ github.ref }}
275
153
154+ - name: Cahce post
155+ uses: ./.github/actions/nix_cache_post
156+
276 Linux-Windows:
157 Linux-Windows:
277− needs: check_versions
278 runs-on: ubuntu-latest
158 runs-on: ubuntu-latest
279 steps:
159 steps:
160+ - name: Increase swap
161+ shell: bash
162+ run: |
163+ free -h
164+
165+ sudo swapoff /mnt/swapfile
166+ sudo fallocate -l 12G /mnt/swapfile
167+ sudo mkswap /mnt/swapfile
168+ sudo swapon /mnt/swapfile
169+
170+ free -h
171+
280 - uses: actions/checkout@v2
172 - uses: actions/checkout@v2
281 with:
173 with:
282 submodules: recursive
174 submodules: recursive
@@ -284,11 +176,15 @@ jobs:
284 - name: Common setup
176 - name: Common setup
285 uses: ./.github/actions/common_setup
177 uses: ./.github/actions/common_setup
286 with:
178 with:
287− authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
179+ key: Linux-Windows-${{ hashFiles('**.nix') }}-${{ hashFiles('stack.yaml') }}-${{ hashFiles('**.cabal') }}
180+ restore-keys: |
181+ Linux-Windows-${{ hashFiles('**.nix') }}-${{ hashFiles('stack.yaml') }}
182+ Linux-Windows-${{ hashFiles('**.nix') }}
183+ Linux-Windows
288
184
289 - name: Build Windows binary
185 - name: Build Windows binary
290 run: |
186 run: |
291− cp -LR $(nix-build -A WindowsCompaRESTBin -j auto --no-out-link)/bin compaREST
187+ cp -LR $(nix-build -A WindowsCompaRESTBin -j auto)/bin compaREST
292
188
293 - name: Upload Windows compaREST bundle
189 - name: Upload Windows compaREST bundle
294 uses: actions/upload-artifact@v2
190 uses: actions/upload-artifact@v2
@@ -296,16 +192,14 @@ jobs:
296 name: compaREST binary – Windows
192 name: compaREST binary – Windows
297 path: compaREST
193 path: compaREST
298
194
299− - name: Zip Release Assets
300− if: github.event_name == 'release'
301− shell: bash
302− run: |
303− zip -r compaREST-Windows.zip compaREST
304−
305 - name: Upload compaREST binary – Windows to release
195 - name: Upload compaREST binary – Windows to release
306 if: github.event_name == 'release'
196 if: github.event_name == 'release'
307 uses: svenstaro/upload-release-action@2.2.1
197 uses: svenstaro/upload-release-action@2.2.1
308 with:
198 with:
309 repo_token: ${{ secrets.GITHUB_TOKEN }}
199 repo_token: ${{ secrets.GITHUB_TOKEN }}
310− file: compaREST-Windows.zip
200+ file: compaREST
201+ asset_name: compaREST binary – Windows
311 tag: ${{ github.ref }}
202 tag: ${{ github.ref }}
203+
204+ - name: Cahce post
205+ uses: ./.github/actions/nix_cache_post
action.yaml+1−1
@@ -29,7 +29,7 @@ inputs:
29 default: "${{ github.event.pull_request.head.sha }}"
29 default: "${{ github.event.pull_request.head.sha }}"
30runs:
30runs:
31 using: "docker"
31 using: "docker"
32− image: "docker://typeable/comparest-github-action:0.0.0.0"
32+ image: "typeable/comparest-github-action:latest"
33 env:
33 env:
34 GITHUB_TOKEN: "${{ inputs.GITHUB_TOKEN }}"
34 GITHUB_TOKEN: "${{ inputs.GITHUB_TOKEN }}"
35 REPO: "${{ inputs.repo }}"
35 REPO: "${{ inputs.repo }}"
app/Data/OpenApi/Compare/Options.hs+72−91
@@ -1,7 +1,7 @@
1module Data.OpenApi.Compare.Options
1module Data.OpenApi.Compare.Options
2− ( Options (..),
2+ ( Options (..)
3− OutputMode (..),
3+ , OutputMode (..)
4− parseOptions,
4+ , parseOptions
5 )
5 )
6where
6where
7
7
@@ -30,105 +30,86 @@ optionsParserInfo :: ParserInfo Options
30optionsParserInfo =
30optionsParserInfo =
31 info
31 info
32 (helper <*> optionsParser)
32 (helper <*> optionsParser)
33− ( fullDesc
33+ (fullDesc
34− <> header "CompaREST"
34+ <> header "CompaREST"
35− <> progDescDoc
35+ <> progDescDoc
36− ( Just $
36+ (Just $
37− par "A tool to check compatibility between two OpenAPI specifications."
37+ par "A tool to check compatibility between two OpenAPI specifications."
38− <$$> hardline <> par "Usage examples" <> hardline
38+ <$$> hardline <> par "Usage examples" <> hardline
39− <$$> indent
39+ <$$> indent
40− 4
40+ 4
41− ( par "Compare files old.yaml with new.yaml and output the resulting report to stdout:"
41+ (par "Compare files old.yaml with new.yaml and output the resulting report to stdout:"
42− <$$> hardline <> indent 4 "comparest -c old.yaml -s new.yaml"
42+ <$$> hardline <> indent 4 "comparest -c old.yaml -s new.yaml"
43− <$$> hardline <> par "Only output breaking changes and write a styled HTML report to file report.html:"
43+ <$$> hardline <> par "Only output breaking changes and write a styled HTML report to file report.html:"
44− <$$> hardline <> indent 4 "comparest -c old.yaml -s new.yaml --only-breaking -o report"
44+ <$$> hardline <> indent 4 "comparest -c old.yaml -s new.yaml --only-breaking -o report"
45− <$$> hardline <> par "Don't output anything, only fail if there are breaking changes:"
45+ <$$> hardline <> par "Don't output anything, only fail if there are breaking changes:"
46− <$$> hardline <> indent 4 "comparest -c old.json -s new.json --silent"
46+ <$$> hardline <> indent 4 "comparest -c old.json -s new.json --silent"
47− <$$> hardline <> par "Write full report suitable for embedding into a GitHub comment to report.html:"
47+ <$$> hardline <> par "Write full report suitable for embedding into a GitHub comment to report.html:"
48− <$$> hardline <> indent 4 "comparest -c old.json -s new.json --folding-block-quotes-style -o report.html"
48+ <$$> hardline <> indent 4 "comparest -c old.json -s new.json --folding-block-quotes-style -o report.html")))
49− )
50− )
51− )
52
49
53optionsParser :: Parser Options
50optionsParser :: Parser Options
54optionsParser =
51optionsParser =
55 Options
52 Options
56 <$> strOption
53 <$> strOption
57− ( short 'c'
54+ (short 'c'
58− <> long "client"
55+ <> long "client"
59− <> help
56+ <> help
60− "A path to the file containing the specification that will be \
57+ "A path to the file containing the specification that will be \
61− \used for the client of the API. Can be either a YAML or JSON file."
58+ \used for the client of the API. Can be either a YAML or JSON file.")
62− )
63 <*> strOption
59 <*> strOption
64− ( short 's'
60+ (short 's'
65− <> long "server"
61+ <> long "server"
66− <> help
62+ <> help
67− "A path to the file containing the specification that will be \
63+ "A path to the file containing the specification that will be \
68− \used for the server of the API. Can be either a YAML or JSON file."
64+ \used for the server of the API. Can be either a YAML or JSON file.")
69− )
70− <*> ( flag'
65+ <*> (flag'
71− Nothing
66+ Nothing
72− ( long "silent"
67+ (long "silent"
73− <> help "Silence all output. Only makes sense in combination with --signal-exit-code."
68+ <> help "Silence all output. Only makes sense in combination with --signal-exit-code.")
74− )
75− <|> flag'
69+ <|> flag'
76− (Just OnlyErrors)
70+ (Just OnlyErrors)
77− ( long "only-breaking"
71+ (long "only-breaking"
78− <> help "Only report breaking changes in the output."
72+ <> help "Only report breaking changes in the output.")
79− )
80− <|> flag'
73+ <|> flag'
81− (Just All)
74+ (Just All)
82− ( long "all"
75+ (long "all"
83− <> help
76+ <> help
84− "Report both incompatible and compatible changes. \
77+ "Report both incompatible and compatible changes. \
85− \Compatible changes will not trigger a failure exit code."
78+ \Compatible changes will not trigger a failure exit code.")
86− )
87− <|> pure (Just All)
79+ <|> pure (Just All))
88− )
89− <*> ( ( FileMode
80+ <*> ((FileMode
90− <$> strOption
81+ <$> strOption
91− ( short 'o' <> long "output"
82+ (short 'o' <> long "output"
92− <> helpDoc
83+ <> helpDoc
93− ( Just $
84+ (Just $
94− par "The file path where the output should be written. If the option is omitted the result will be written to stdout."
85+ par "The file path where the output should be written. If the option is omitted the result will be written to stdout."
95− <$$> hardline <> par "The file extension is used to determine the type of the output file."
86+ <$$> hardline <> par "The file extension is used to determine the type of the output file."
96− <$$> hardline <> par "Supports many formats such as markdown, html, rtf, doc, txt, rst, and many more."
87+ <$$> hardline <> par "Supports many formats such as markdown, html, rtf, doc, txt, rst, and many more."
97− <$$> hardline <> par "Leave out the extension to produce a self-contained HTML report with styling."
88+ <$$> hardline <> par "Leave out the extension to produce a self-contained HTML report with styling.")))
98− )
99− )
100− )
101− <|> pure StdoutMode
89+ <|> pure StdoutMode)
102− )
103− <*> ( flag'
90+ <*> (flag'
104− FoldingBlockquotesTreeStyle
91+ FoldingBlockquotesTreeStyle
105− ( long "folding-block-quotes-style"
92+ (long "folding-block-quotes-style"
93+ <> help
94+ "The report tree is structured using \
95+ \summary/detail HTML elements and indented using \
96+ \block quotes. This style renders well on GitHub.\
97+ \Intended for HTML output format. Markdown has rendering \
98+ \bugs on GitHub.")
99+ <|> flag'
100+ HeadersTreeStyle
101+ (long "header-style"
106 <> help
102 <> help
107 "The report tree is structured using \
103 "The report tree is structured using \
108− \summary/detail HTML elements and indented using \
109− \block quotes. This style renders well on GitHub.\
110− \Intended for HTML output format. Markdown has rendering \
111− \bugs on GitHub."
112− )
113− <|> flag'
114− HeadersTreeStyle
115− ( long "header-style"
116− <> help
117− "The report tree is structured using \
118− \increasing levels of headers."
104+ \increasing levels of headers.")
119− )
120− <|> pure HeadersTreeStyle
105+ <|> pure HeadersTreeStyle)
121− )
122− <*> switch
106+ <*> switch
123− ( long "signal-exit-code"
107+ (long "signal-exit-code"
124− <> helpDoc
108+ <> helpDoc (Just $
125− ( Just $
126 par "Signal API compatibility with the exit code."
109 par "Signal API compatibility with the exit code."
127 <$$> hardline <> par "Exit with 0 if there are no breaking changes."
110 <$$> hardline <> par "Exit with 0 if there are no breaking changes."
128 <$$> par "Exit with 1 if there are breaking changes."
111 <$$> par "Exit with 1 if there are breaking changes."
129− <$$> par "Exit with 2 if could not determine compatibility."
112+ <$$> par "Exit with 2 if could not determine compatibility."))
130− )
131− )
132
113
133par :: String -> Doc
114par :: String -> Doc
134par = foldr1 (</>) . fmap string . words
115par = foldr1 (</>) . fmap string . words
app/FormatHeuristic.hs+1−1
@@ -2,7 +2,7 @@
2-- Originally based on:
2-- Originally based on:
3-- https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/App/FormatHeuristics.hs
3-- https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/App/FormatHeuristics.hs
4module FormatHeuristic
4module FormatHeuristic
5− ( formatFromFilePath,
5+ ( formatFromFilePath
6 )
6 )
7where
7where
8
8
ci/policeman.nixdeleted−4
@@ -1,4 +0,0 @@
1−{ sources ? import ../nix/sources.nix
2−, pkgs ? import sources.nixpkgs { }
3−}:
4−pkgs.haskellPackages.policeman
compaREST.cabal−5
@@ -14,9 +14,6 @@ extra-doc-files: README.md
14 CHANGELOG.md
14 CHANGELOG.md
15tested-with: GHC == 8.10.4
15tested-with: GHC == 8.10.4
16extra-source-files: awsm-css/dist/awsm.min.css
16extra-source-files: awsm-css/dist/awsm.min.css
17−data-files:
18− test/golden/**/*.yaml
19− test/golden/**/*.md
20
17
21common common-options
18common common-options
22 ghc-options:
19 ghc-options:
@@ -206,8 +203,6 @@ test-suite compaREST-tests
206 other-modules:
203 other-modules:
207 Spec.Golden.Extra
204 Spec.Golden.Extra
208 Spec.Golden.TraceTree
205 Spec.Golden.TraceTree
209− Paths_compaREST
210− autogen-modules: Paths_compaREST
211 build-depends:
206 build-depends:
212 , compaREST
207 , compaREST
213 , tasty-golden
208 , tasty-golden
default.nix+11−9
@@ -24,11 +24,12 @@ let
24 dontPatchELF = false;
24 dontPatchELF = false;
25 enableDeadCodeElimination = true;
25 enableDeadCodeElimination = true;
26 ghcOptions = [
26 ghcOptions = [
27− "-O2"
27+ # "-O2"
28− "-fexpose-all-unfoldings"
28+ # "-fexpose-all-unfoldings"
29− "-fspecialise-aggressively"
29+ # "-fspecialise-aggressively"
30+ "-O0"
30 ];
31 ];
31− packages.pandoc.ghcOptions = [ "-O1" ];
32+ # packages.pandoc.ghcOptions = [ "-O1" ];
32 packages.compaREST.src = nix-filter {
33 packages.compaREST.src = nix-filter {
33 root = ./.;
34 root = ./.;
34 name = "compaREST-src";
35 name = "compaREST-src";
@@ -98,6 +99,8 @@ let
98
99
99 WindowsCompaRESTBin = hsPkgs.projectCross.mingwW64.hsPkgs.compaREST.components.exes.compaREST;
100 WindowsCompaRESTBin = hsPkgs.projectCross.mingwW64.hsPkgs.compaREST.components.exes.compaREST;
100in
101in
102+builtins.trace
103+ hsPkgs.compaREST.components.exes
101{
104{
102 inherit
105 inherit
103 compaRESTImage
106 compaRESTImage
@@ -105,10 +108,9 @@ in
105 compaRESTStaticBin
108 compaRESTStaticBin
106 compaRESTBin
109 compaRESTBin
107 hsPkgs
110 hsPkgs
108− macOSCompaRESTBundle
109− WindowsCompaRESTBin;
110
111
111− # We use the static version so that we don't have to rebuild everything on CI.
112+ macOSCompaRESTBundle
112− # The only binaries build on CI are static.
113+ WindowsCompaRESTBin
114+ ;
113− test = hsPkgs.projectCross.musl64.hsPkgs.compaREST.components.tests.compaREST-tests;
115+ test = hsPkgs.compaREST.components.tests.compaREST-tests;
114}
116}
nix/ci.nixdeleted−6
@@ -1,6 +0,0 @@
1−{ sources ? import ./sources.nix
2−, pkgs ? import sources.nixpkgs { }
3−}:
4−pkgs.mkShell {
5− packages = [ pkgs.haskellPackages.fourmolu ];
6−}
policeman.jsondeleted−6
@@ -1,6 +0,0 @@
1−[{
2− "file": "compaREST.cabal",
3− "annotation_level": "notice",
4− "end_line": 0,
5− "start_line": 0
6−}]
src/Data/HList.hs+11−11
@@ -1,11 +1,11 @@
1module Data.HList
1module Data.HList
2− ( Has,
2+ ( Has
3− HasAll,
3+ , HasAll
4− getH,
4+ , getH
5− HList (..),
5+ , HList (..)
6− singletonH,
6+ , singletonH
7− ReassembleHList,
7+ , ReassembleHList
8− reassemble,
8+ , reassemble
9 )
9 )
10where
10where
11
11
@@ -40,8 +40,8 @@ instance (Has' x xs t, HeadEq x (y : xs) ~ 'False) => Has' x (y ': xs) 'False wh
40 {-# INLINE getH #-}
40 {-# INLINE getH #-}
41
41
42instance
42instance
43− TypeError ( 'ShowType x ':<>: 'Text " is not a part of the list.") =>
43+ TypeError ('ShowType x ':<>: 'Text " is not a part of the list.")
44− Has' x '[] 'False
44+ => Has' x '[] 'False
45 where
45 where
46 getH HNil = undefined
46 getH HNil = undefined
47 {-# INLINE getH #-}
47 {-# INLINE getH #-}
@@ -74,8 +74,8 @@ instance ReassembleHList' (x ': xs) '[] 'False where
74 {-# INLINE reassemble #-}
74 {-# INLINE reassemble #-}
75
75
76instance
76instance
77− (Has y xs, ReassembleHList' xs ys f, (xs == (y ': ys)) ~ 'False) =>
77+ (Has y xs, ReassembleHList' xs ys f, (xs == (y ': ys)) ~ 'False)
78− ReassembleHList' xs (y ': ys) 'False
78+ => ReassembleHList' xs (y ': ys) 'False
79 where
79 where
80 reassemble xs = getH @y xs `HCons` reassemble xs
80 reassemble xs = getH @y xs `HCons` reassemble xs
81 {-# INLINE reassemble #-}
81 {-# INLINE reassemble #-}
src/Data/OpenApi/Compare/Behavior.hs+11−11
@@ -1,15 +1,15 @@
1module Data.OpenApi.Compare.Behavior
1module Data.OpenApi.Compare.Behavior
2− ( BehaviorLevel (..),
2+ ( BehaviorLevel (..)
3− Behavable (..),
3+ , Behavable (..)
4− IssueKind (..),
4+ , IssueKind (..)
5− Issuable (..),
5+ , Issuable (..)
6− Orientation (..),
6+ , Orientation (..)
7− toggleOrientation,
7+ , toggleOrientation
8− Behavior,
8+ , Behavior
9− AnIssue (..),
9+ , AnIssue (..)
10− withClass,
10+ , withClass
11− anIssueKind,
11+ , anIssueKind
12− relatedAnIssues,
12+ , relatedAnIssues
13 )
13 )
14where
14where
15
15
src/Data/OpenApi/Compare/Common.hs+1−1
@@ -1,5 +1,5 @@
1module Data.OpenApi.Compare.Common
1module Data.OpenApi.Compare.Common
2− ( zipAll,
2+ ( zipAll
3 )
3 )
4where
4where
5
5
src/Data/OpenApi/Compare/Formula.hs+21−31
@@ -1,15 +1,14 @@
1module Data.OpenApi.Compare.Formula
1module Data.OpenApi.Compare.Formula
2− ( FormulaF,
2+ ( FormulaF
3− VarRef,
3+ , VarRef
4− variable,
4+ , variable
5− eitherOf,
5+ , eitherOf
6− anError,
6+ , anError
7− errors,
7+ , errors
8− calculate,
8+ , calculate
9− maxFixpoint,
9+ , maxFixpoint
10− mapErrors,
10+ , mapErrors
11− )
12−where
11+ ) where
13
12
14import Data.Kind
13import Data.Kind
15import qualified Data.List.NonEmpty as NE
14import qualified Data.List.NonEmpty as NE
@@ -25,24 +24,15 @@ type VarRef = Int
25-- fixpoints always exist, i.e. that @x = f x@ has at least one solution.
24-- fixpoints always exist, i.e. that @x = f x@ has at least one solution.
26data FormulaF (q :: k -> k -> Type) (f :: k -> Type) (r :: k) (a :: Type) where
25data FormulaF (q :: k -> k -> Type) (f :: k -> Type) (r :: k) (a :: Type) where
27 Result :: a -> FormulaF q f r a
26 Result :: a -> FormulaF q f r a
28− Errors ::
29− !(P.PathsPrefixTree q f r) ->
27+ Errors :: !(P.PathsPrefixTree q f r) -> FormulaF q f r a
30− -- | invariant: never empty
28+ -- ^ invariant: never empty
31− FormulaF q f r a
32− Apply ::
33− FormulaF q f r (b -> c) ->
29+ Apply :: FormulaF q f r (b -> c) -> FormulaF q f r b -> (c -> a) -> FormulaF q f r a
34− FormulaF q f r b ->
35− (c -> a) ->
36− -- | invariant: at least one of LHS and RHS is not 'Errors', and they are
30+ -- ^ invariant: at least one of LHS and RHS is not 'Errors', and they are
37 -- both not 'Result'
31 -- both not 'Result'
38− FormulaF q f r a
39− SelectFirst ::
40− NE.NonEmpty (SomeFormulaF b) ->
32+ SelectFirst :: NE.NonEmpty (SomeFormulaF b)
41− !(P.PathsPrefixTree q f r) ->
33+ -> !(P.PathsPrefixTree q f r) -> (b -> a) -> FormulaF q f r a
42− (b -> a) ->
43− -- | invariant: the list doesn't contain any 'Result's, 'Errors' or
34+ -- ^ invariant: the list doesn't contain any 'Result's, 'Errors' or
44 -- 'SelectFirst'
35 -- 'SelectFirst'
45− FormulaF q f r a
46 Variable :: !VarRef -> a -> FormulaF q f r a
36 Variable :: !VarRef -> a -> FormulaF q f r a
47
37
48mkApply :: FormulaF q f r (b -> c) -> FormulaF q f r b -> (c -> a) -> FormulaF q f r a
38mkApply :: FormulaF q f r (b -> c) -> FormulaF q f r b -> (c -> a) -> FormulaF q f r a
@@ -54,13 +44,13 @@ mkApply f x h = Apply f x h
54mkSelectFirst :: [SomeFormulaF b] -> P.PathsPrefixTree q f r -> (b -> a) -> FormulaF q f r a
44mkSelectFirst :: [SomeFormulaF b] -> P.PathsPrefixTree q f r -> (b -> a) -> FormulaF q f r a
55mkSelectFirst fs allE h = case foldMap check fs of
45mkSelectFirst fs allE h = case foldMap check fs of
56 (First (Just x), _) -> Result (h x)
46 (First (Just x), _) -> Result (h x)
57− (First Nothing, x : xs) -> SelectFirst (x NE.:| xs) allE h
47+ (First Nothing, x:xs) -> SelectFirst (x NE.:| xs) allE h
58 (First Nothing, []) -> Errors allE
48 (First Nothing, []) -> Errors allE
59 where
49 where
60 check (SomeFormulaF (Result x)) = (First (Just x), mempty)
50 check (SomeFormulaF (Result x)) = (First (Just x), mempty)
61 check (SomeFormulaF (Errors _)) = (mempty, mempty)
51 check (SomeFormulaF (Errors _)) = (mempty, mempty)
62− check (SomeFormulaF (SelectFirst xs _ h')) =
52+ check (SomeFormulaF (SelectFirst xs _ h'))
63− (mempty, NE.toList (fmap (fmap h') xs))
53+ = (mempty, NE.toList (fmap (fmap h') xs))
64 check x = (mempty, [x])
54 check x = (mempty, [x])
65
55
66data SomeFormulaF (a :: Type) where
56data SomeFormulaF (a :: Type) where
@@ -106,7 +96,7 @@ calculate (Apply f x h) = case calculate f of
106 Right x' -> Right (h (f' x'))
96 Right x' -> Right (h (f' x'))
107calculate (SelectFirst xs e h) = go (NE.toList xs)
97calculate (SelectFirst xs e h) = go (NE.toList xs)
108 where
98 where
109− go (SomeFormulaF r : rs) = case calculate r of
99+ go (SomeFormulaF r:rs) = case calculate r of
110 Left _ -> go rs
100 Left _ -> go rs
111 Right x -> Right (h x)
101 Right x -> Right (h x)
112 go [] = Left e
102 go [] = Left e
src/Data/OpenApi/Compare/Memo.hs+66−104
@@ -1,24 +1,22 @@
1{-# LANGUAGE AllowAmbiguousTypes #-}
1{-# LANGUAGE AllowAmbiguousTypes #-}
2−
3-- | Utilities for effectfully memoizing other, more effectful functions.
2-- | Utilities for effectfully memoizing other, more effectful functions.
4module Data.OpenApi.Compare.Memo
3module Data.OpenApi.Compare.Memo
5− ( MonadMemo,
4+ ( MonadMemo
6− MemoState,
5+ , MemoState
7− runMemo,
6+ , runMemo
8− modifyMemoNonce,
7+ , modifyMemoNonce
9− KnotTier (..),
8+ , KnotTier(..)
10− unknot,
9+ , unknot
11− memoWithKnot,
10+ , memoWithKnot
12− memoTaggedWithKnot,
11+ , memoTaggedWithKnot
13− )
14−where
12+ ) where
15
13
16import Control.Monad.State
14import Control.Monad.State
17import Data.Dynamic
15import Data.Dynamic
18import qualified Data.Map as M
16import qualified Data.Map as M
19import Data.Tagged
17import Data.Tagged
20−import qualified Data.TypeRepMap as T
21import Data.Void
18import Data.Void
19+import qualified Data.TypeRepMap as T
22import Type.Reflection
20import Type.Reflection
23
21
24data Progress a = Finished a | Started | TyingKnot Dynamic
22data Progress a = Finished a | Started | TyingKnot Dynamic
@@ -31,23 +29,16 @@ data MemoState s = MemoState s (T.TypeRepMap MemoMap)
31-- | An effectful memoization monad.
29-- | An effectful memoization monad.
32type MonadMemo s m = MonadState (MemoState s) m
30type MonadMemo s m = MonadState (MemoState s) m
33
31
34−memoStateLookup ::
32+memoStateLookup
35− forall k v s.
36− (Typeable k, Typeable v, Ord k) =>
33+ :: forall k v s. (Typeable k, Typeable v, Ord k)
37− k ->
38− MemoState s ->
39− Maybe (Progress v)
34+ => k -> MemoState s -> Maybe (Progress v)
40memoStateLookup k (MemoState _ t) = case T.lookup @(k, v) t of
35memoStateLookup k (MemoState _ t) = case T.lookup @(k, v) t of
41 Just (MemoMap m) -> M.lookup k m
36 Just (MemoMap m) -> M.lookup k m
42 Nothing -> Nothing
37 Nothing -> Nothing
43
38
44−memoStateInsert ::
39+memoStateInsert
45− forall k v s.
46− (Typeable k, Typeable v, Ord k) =>
40+ :: forall k v s. (Typeable k, Typeable v, Ord k)
47− k ->
48− Progress v ->
49− MemoState s ->
41+ => k -> Progress v -> MemoState s -> MemoState s
50− MemoState s
51memoStateInsert k x (MemoState s t) = MemoState s $ T.insert (MemoMap m'') t
42memoStateInsert k x (MemoState s t) = MemoState s $ T.insert (MemoMap m'') t
52 where
43 where
53 m'' = M.insert k x m'
44 m'' = M.insert k x m'
@@ -68,23 +59,19 @@ runMemo s = (`evalStateT` MemoState s T.empty)
68-- | A description of how to effectfully tie knots in type @v@, using the @m@
59-- | A description of how to effectfully tie knots in type @v@, using the @m@
69-- monad, and by sharing some @d@ data among the recursive instances.
60-- monad, and by sharing some @d@ data among the recursive instances.
70data KnotTier v d m = KnotTier
61data KnotTier v d m = KnotTier
71− { -- | Create some data that will be connected to this knot
62+ { onKnotFound :: m d -- ^ Create some data that will be connected to this knot
72− onKnotFound :: m d
73− , -- | This is what the knot will look like as a value
63+ , onKnotUsed :: d -> m v -- ^ This is what the knot will look like as a value
74 -- to the inner computations
64 -- to the inner computations
75− onKnotUsed :: d -> m v
76− , -- | Once we're done and we're outside, tie the
65+ , tieKnot :: d -> v -> m v -- ^ Once we're done and we're outside, tie the
77 -- knot using the datum
66 -- knot using the datum
78− tieKnot :: d -> v -> m v
79 }
67 }
80
68
81unknot :: KnotTier v Void m
69unknot :: KnotTier v Void m
82−unknot =
83− KnotTier
70+unknot = KnotTier
84− { onKnotFound = error "Recursion detected"
71+ { onKnotFound = error "Recursion detected"
85− , onKnotUsed = absurd
72+ , onKnotUsed = absurd
86− , tieKnot = absurd
73+ , tieKnot = absurd
87− }
74+ }
88
75
89-- | Run a potentially recursive computation. The provided key will be used to
76-- | Run a potentially recursive computation. The provided key will be used to
90-- refer to the result of this computation. If during the computation, another
77-- refer to the result of this computation. If during the computation, another
@@ -93,72 +80,47 @@ unknot =
93--
80--
94-- If another attempt to run the computation with the same key is made
81-- If another attempt to run the computation with the same key is made
95-- *after we're done*, we will return the memoized value.
82-- *after we're done*, we will return the memoized value.
96−memoWithKnot ::
83+memoWithKnot
97− forall k v d m s.
84+ :: forall k v d m s.
98− (Typeable k, Typeable v, Typeable d, Ord k, MonadMemo s m) =>
85+ (Typeable k, Typeable v, Typeable d, Ord k, MonadMemo s m)
99− KnotTier v d m ->
86+ => KnotTier v d m
100− -- | the computation to memoize
87+ -> m v -- ^ the computation to memoize
101− m v ->
102− -- | key for memoization
88+ -> k -- ^ key for memoization
103− k ->
104− m v
89+ -> m v
105−memoWithKnot tier f k =
106− memoStateLookup @k @v k <$> get >>= \case
90+memoWithKnot tier f k = memoStateLookup @k @v k <$> get >>= \case
107− Just (Finished v) -> pure v
91+ Just (Finished v) -> pure v
108− Just Started -> do
92+ Just Started -> do
109− d <- onKnotFound tier
93+ d <- onKnotFound tier
110− modify $ memoStateInsert @k @v k (TyingKnot $ toDyn d)
94+ modify $ memoStateInsert @k @v k (TyingKnot $ toDyn d)
111− onKnotUsed tier d
95+ onKnotUsed tier d
112− Just (TyingKnot dyn) -> case fromDynamic dyn of
96+ Just (TyingKnot dyn) -> case fromDynamic dyn of
113− Just d -> onKnotUsed tier d
97+ Just d -> onKnotUsed tier d
114− Nothing ->
115− error $
116− "Type mismatch when examining the knot of "
98+ Nothing -> error $ "Type mismatch when examining the knot of "
117− <> show (typeRep @(k -> v))
99+ <> show (typeRep @(k -> v)) <> ": expected " <> show (typeRep @d)
118− <> ": expected "
119− <> show (typeRep @d)
120− <> ", got "
121− <> show (dynTypeRep dyn)
100+ <> ", got " <> show (dynTypeRep dyn)
122− Nothing -> do
101+ Nothing -> do
123− modify $ memoStateInsert @k @v k Started
102+ modify $ memoStateInsert @k @v k Started
124− v <- f
103+ v <- f
125− v' <-
126− memoStateLookup @k @v k <$> get >>= \case
104+ v' <- memoStateLookup @k @v k <$> get >>= \case
127− Just Started -> pure v
105+ Just Started -> pure v
128− Just (TyingKnot dyn) -> case fromDynamic dyn of
106+ Just (TyingKnot dyn) -> case fromDynamic dyn of
129− Just d -> tieKnot tier d v
107+ Just d -> tieKnot tier d v
130− Nothing ->
131− error $
132− "Type mismatch when tying the knot of "
108+ Nothing -> error $ "Type mismatch when tying the knot of "
133− <> show (typeRep @(k -> v))
109+ <> show (typeRep @(k -> v)) <> ": expected " <> show (typeRep @d)
134− <> ": expected "
135− <> show (typeRep @d)
136− <> ", got "
137− <> show (dynTypeRep dyn)
110+ <> ", got " <> show (dynTypeRep dyn)
138− Just (Finished _) ->
139− error $
140− "Unexpected Finished when memoizing "
111+ Just (Finished _) -> error $ "Unexpected Finished when memoizing "
141− <> show (typeRep @(k -> v))
112+ <> show (typeRep @(k -> v))
142− Nothing -> pure v
113+ Nothing -> pure v
143− -- Normally this would be an error, but the underlying monad can refuse
114+ -- Normally this would be an error, but the underlying monad can refuse
144− -- to remember memoization state
115+ -- to remember memoization state
145− modify $ memoStateInsert @k @v k (Finished v')
116+ modify $ memoStateInsert @k @v k (Finished v')
146− pure v'
117+ pure v'
147
118
148-- | Disambiguate memoized computations with an arbitrary tag.
119-- | Disambiguate memoized computations with an arbitrary tag.
149−memoTaggedWithKnot ::
120+memoTaggedWithKnot
150− forall t k v d m s.
121+ :: forall t k v d m s.
151− ( Typeable t
122+ ( Typeable t, Typeable k, Typeable v, Typeable d
152− , Typeable k
153− , Typeable v
154− , Typeable d
155− , Ord k
156− , MonadMemo s m
123+ , Ord k, MonadMemo s m )
157− ) =>
158− KnotTier v d m ->
124+ => KnotTier v d m -> m v -> k -> m v
159− m v ->
160− k ->
161− m v
162−memoTaggedWithKnot tier f k =
163− withTypeable (typeRepKind $ typeRep @t) $
125+memoTaggedWithKnot tier f k = withTypeable (typeRepKind $ typeRep @t) $
164− memoWithKnot tier f (Tagged @t k)
126+ memoWithKnot tier f (Tagged @t k)
src/Data/OpenApi/Compare/Paths.hs+9−9
@@ -2,17 +2,17 @@
2-- collection of datatypes that "contain" eachother in some form of tree
2-- collection of datatypes that "contain" eachother in some form of tree
3-- structure.
3-- structure.
4module Data.OpenApi.Compare.Paths
4module Data.OpenApi.Compare.Paths
5− ( NiceQuiver,
5+ ( NiceQuiver
6− AdditionalQuiverConstraints,
6+ , AdditionalQuiverConstraints
7− Paths (..),
7+ , Paths (..)
8− DiffPaths (..),
8+ , DiffPaths (..)
9− catDiffPaths,
9+ , catDiffPaths
10− AnItem (..),
10+ , AnItem (..)
11− step,
11+ , step
12
12
13 -- * Reexports
13 -- * Reexports
14− (>>>),
14+ , (>>>)
15− (<<<),
15+ , (<<<)
16 )
16 )
17where
17where
18
18
src/Data/OpenApi/Compare/PathsPrefixTree.hs+37−37
@@ -1,22 +1,22 @@
1{-# LANGUAGE QuantifiedConstraints #-}
1{-# LANGUAGE QuantifiedConstraints #-}
2
2
3module Data.OpenApi.Compare.PathsPrefixTree
3module Data.OpenApi.Compare.PathsPrefixTree
4− ( PathsPrefixTree (PathsPrefixNode),
4+ ( PathsPrefixTree (PathsPrefixNode)
5− AStep (..),
5+ , AStep (..)
6− empty,
6+ , empty
7− singleton,
7+ , singleton
8− fromList,
8+ , fromList
9− null,
9+ , null
10− foldWith,
10+ , foldWith
11− toList,
11+ , toList
12− filter,
12+ , filter
13− filterWithKey,
13+ , filterWithKey
14− takeSubtree,
14+ , takeSubtree
15− lookup,
15+ , lookup
16− embed,
16+ , embed
17− size,
17+ , size
18− partition,
18+ , partition
19− map,
19+ , map
20 )
20 )
21where
21where
22
22
@@ -35,7 +35,7 @@ import qualified Data.TypeRepMap as TRM
35import qualified Data.Vector as V
35import qualified Data.Vector as V
36import qualified GHC.Exts as Exts
36import qualified GHC.Exts as Exts
37import Type.Reflection
37import Type.Reflection
38−import Prelude hiding (filter, lookup, map, null)
38+import Prelude hiding (filter, map, null, lookup)
39
39
40-- | A list of @AnItem r f@, but optimized into a prefix tree.
40-- | A list of @AnItem r f@, but optimized into a prefix tree.
41data PathsPrefixTree (q :: k -> k -> Type) (f :: k -> Type) (r :: k) = PathsPrefixTree
41data PathsPrefixTree (q :: k -> k -> Type) (f :: k -> Type) (r :: k) = PathsPrefixTree
@@ -102,11 +102,11 @@ deriving stock instance Eq (PathsPrefixTree q f a)
102
102
103-- Kind of orphan. Treat the map as an infinite tuple of @Maybe (f a)@'s, where
103-- Kind of orphan. Treat the map as an infinite tuple of @Maybe (f a)@'s, where
104-- the components are ordered by the @SomeTypeRep@ of the @a@.
104-- the components are ordered by the @SomeTypeRep@ of the @a@.
105−compareTRM ::
105+compareTRM
106− (forall a. Typeable a => Ord (f a)) =>
106+ :: (forall a. Typeable a => Ord (f a))
107− TRM.TypeRepMap f ->
107+ => TRM.TypeRepMap f
108− TRM.TypeRepMap f ->
108+ -> TRM.TypeRepMap f
109− Ordering
109+ -> Ordering
110compareTRM s1 s2 =
110compareTRM s1 s2 =
111 foldMap (\k -> compareMaybe compareW (M.lookup k m1) (M.lookup k m2)) mKeys
111 foldMap (\k -> compareMaybe compareW (M.lookup k m1) (M.lookup k m2)) mKeys
112 where
112 where
@@ -116,11 +116,11 @@ compareTRM s1 s2 =
116 compareMaybe _ Nothing (Just _) = LT
116 compareMaybe _ Nothing (Just _) = LT
117 compareMaybe _ (Just _) Nothing = GT
117 compareMaybe _ (Just _) Nothing = GT
118 compareMaybe cmp (Just x) (Just y) = cmp x y
118 compareMaybe cmp (Just x) (Just y) = cmp x y
119− compareW ::
119+ compareW
120− (forall a. Typeable a => Ord (f a)) =>
120+ :: (forall a. Typeable a => Ord (f a))
121− TRM.WrapTypeable f ->
121+ => TRM.WrapTypeable f
122− TRM.WrapTypeable f ->
122+ -> TRM.WrapTypeable f
123− Ordering
123+ -> Ordering
124 compareW (TRM.WrapTypeable (x :: f a)) (TRM.WrapTypeable (y :: f b))
124 compareW (TRM.WrapTypeable (x :: f a)) (TRM.WrapTypeable (y :: f b))
125 | Just Refl <- testEquality (typeRep @a) (typeRep @b) = compare x y
125 | Just Refl <- testEquality (typeRep @a) (typeRep @b) = compare x y
126 | otherwise = EQ -- unreachable
126 | otherwise = EQ -- unreachable
@@ -172,10 +172,10 @@ instance Monoid (ASet a) where
172 mempty = AnEmptySet
172 mempty = AnEmptySet
173
173
174data AStep (q :: k -> k -> Type) (f :: k -> Type) (r :: k) (a :: k) where
174data AStep (q :: k -> k -> Type) (f :: k -> Type) (r :: k) (a :: k) where
175− AStep ::
175+ AStep
176− NiceQuiver q r a =>
176+ :: NiceQuiver q r a =>
177− !(M.Map (q r a) (PathsPrefixTree q f a)) ->
177+ !(M.Map (q r a) (PathsPrefixTree q f a))
178− AStep q f r a
178+ -> AStep q f r a
179
179
180mapAStep :: (forall x. f x -> f x) -> AStep q f r a -> AStep q f r a
180mapAStep :: (forall x. f x -> f x) -> AStep q f r a -> AStep q f r a
181mapAStep f (AStep m) = AStep $ M.map (map f) m
181mapAStep f (AStep m) = AStep $ M.map (map f) m
@@ -215,12 +215,12 @@ null :: PathsPrefixTree q f r -> Bool
215null (PathsPrefixTree AnEmptySet s) = all (\(TRM.WrapTypeable (AStep x)) -> all null x) (Exts.toList s)
215null (PathsPrefixTree AnEmptySet s) = all (\(TRM.WrapTypeable (AStep x)) -> all null x) (Exts.toList s)
216null _ = False
216null _ = False
217
217
218−foldWith ::
218+foldWith
219− forall q f m r.
219+ :: forall q f m r.
220− Monoid m =>
220+ Monoid m
221− (forall a. Ord (f a) => Paths q r a -> f a -> m) ->
221+ => (forall a. Ord (f a) => Paths q r a -> f a -> m)
222− PathsPrefixTree q f r ->
222+ -> PathsPrefixTree q f r
223− m
223+ -> m
224foldWith k = goTPT Root
224foldWith k = goTPT Root
225 where
225 where
226 goTPT :: forall a. Paths q r a -> PathsPrefixTree q f a -> m
226 goTPT :: forall a. Paths q r a -> PathsPrefixTree q f a -> m
src/Data/OpenApi/Compare/References.hs+8−8
@@ -1,9 +1,9 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2
2
3module Data.OpenApi.Compare.References
3module Data.OpenApi.Compare.References
4− ( Step (..),
4+ ( Step (..)
5− dereference,
5+ , dereference
6− Typeable,
6+ , Typeable
7 )
7 )
8where
8where
9
9
@@ -18,11 +18,11 @@ instance Typeable a => Steppable (Referenced a) a where
18 data Step (Referenced a) a = InlineStep
18 data Step (Referenced a) a = InlineStep
19 deriving stock (Eq, Ord, Show)
19 deriving stock (Eq, Ord, Show)
20
20
21−dereference ::
21+dereference
22− Typeable a =>
22+ :: Typeable a
23− Traced (Definitions a) ->
23+ => Traced (Definitions a)
24− Traced (Referenced a) ->
24+ -> Traced (Referenced a)
25− Traced a
25+ -> Traced a
26dereference defs x = case extract x of
26dereference defs x = case extract x of
27 Inline a ->
27 Inline a ->
28 traced (ask x >>> step InlineStep) a
28 traced (ask x >>> step InlineStep) a
src/Data/OpenApi/Compare/Report.hs+120−140
@@ -1,13 +1,13 @@
1module Data.OpenApi.Compare.Report
1module Data.OpenApi.Compare.Report
2− ( generateReport,
2+ ( generateReport
3− CheckerOutput (..),
3+ , CheckerOutput(..)
4− ReportInput (..),
4+ , ReportInput (..)
5− segregateIssues,
5+ , segregateIssues
6− ReportStatus (..),
6+ , ReportStatus (..)
7− Pandoc,
7+ , Pandoc
8− ReportConfig (..),
8+ , ReportConfig (..)
9− ReportTreeStyle (..),
9+ , ReportTreeStyle (..)
10− ReportMode (..),
10+ , ReportMode (..)
11 )
11 )
12where
12where
13
13
@@ -30,8 +30,8 @@ import qualified Data.OpenApi.Compare.PathsPrefixTree as P hiding (empty)
30import Data.OpenApi.Compare.Report.Jet
30import Data.OpenApi.Compare.Report.Jet
31import Data.OpenApi.Compare.Subtree (invertIssueOrientationP)
31import Data.OpenApi.Compare.Subtree (invertIssueOrientationP)
32import Data.OpenApi.Compare.Validate.OpenApi
32import Data.OpenApi.Compare.Validate.OpenApi
33−import Data.OpenApi.Compare.Validate.Schema.Issues
34import Data.OpenApi.Compare.Validate.Schema.TypedJson
33import Data.OpenApi.Compare.Validate.Schema.TypedJson
34+import Data.OpenApi.Compare.Validate.Schema.Issues
35import Data.OpenUnion
35import Data.OpenUnion
36import Data.OpenUnion.Extra
36import Data.OpenUnion.Extra
37import Data.Set
37import Data.Set
@@ -54,27 +54,22 @@ data CheckerOutput = CheckerOutput
54 deriving anyclass (ToJSON)
54 deriving anyclass (ToJSON)
55
55
56data ReportInput = ReportInput
56data ReportInput = ReportInput
57− { -- | forward 'CertainIssue', 'ProbablyIssue' and 'Comment'
58− breakingChanges :: Changes
57+ { breakingChanges :: Changes -- ^ forward 'CertainIssue', 'ProbablyIssue' and 'Comment'
59− , -- | backward 'CertainIssue', 'ProbablyIssue' and 'Comment', except those shadowed by 'relatedIssues'
58+ , nonBreakingChanges :: Changes -- ^ backward 'CertainIssue', 'ProbablyIssue' and 'Comment', except those shadowed by 'relatedIssues'
60− nonBreakingChanges :: Changes
61− , -- | forward and backward 'Unsupported' (assumed to be the same anyway)
59+ , unsupportedChanges :: Changes -- ^ forward and backward 'Unsupported' (assumed to be the same anyway)
62− unsupportedChanges :: Changes
63− , -- | forward and backward 'SchemaInvalid' (assumed to be the same anyway)
64− schemaIssues :: Changes
60+ , schemaIssues :: Changes -- ^ forward and backward 'SchemaInvalid' (assumed to be the same anyway)
65 }
61 }
66 deriving stock (Generic)
62 deriving stock (Generic)
67 deriving (Semigroup, Monoid) via (Generically ReportInput)
63 deriving (Semigroup, Monoid) via (Generically ReportInput)
68 deriving anyclass (ToJSON)
64 deriving anyclass (ToJSON)
69
65
70segregateIssues :: CheckerOutput -> ReportInput
66segregateIssues :: CheckerOutput -> ReportInput
71−segregateIssues CheckerOutput {forwardChanges = fwd, backwardChanges = bck} =
67+segregateIssues CheckerOutput {forwardChanges = fwd, backwardChanges = bck} = ReportInput
72− ReportInput
73− { breakingChanges = P.filter isBreaking fwd
68+ { breakingChanges = P.filter isBreaking fwd
74− , nonBreakingChanges = invertIssueOrientationP $ P.filterWithKey isNonBreaking bck
69+ , nonBreakingChanges = invertIssueOrientationP $ P.filterWithKey isNonBreaking bck
75− , unsupportedChanges = P.filter isUnsupported fwd <> P.filter isUnsupported bck
70+ , unsupportedChanges = P.filter isUnsupported fwd <> P.filter isUnsupported bck
76− , schemaIssues = P.filter isSchemaIssue fwd <> P.filter isSchemaIssue bck
71+ , schemaIssues = P.filter isSchemaIssue fwd <> P.filter isSchemaIssue bck
77− }
72+ }
78 where
73 where
79 isBreaking i = anIssueKind i `elem` [CertainIssue, ProbablyIssue, Comment]
74 isBreaking i = anIssueKind i `elem` [CertainIssue, ProbablyIssue, Comment]
80 isNonBreaking :: Paths Behave 'APILevel a -> AnIssue a -> Bool
75 isNonBreaking :: Paths Behave 'APILevel a -> AnIssue a -> Bool
@@ -111,7 +106,8 @@ twoRowTable x = simpleTable (para . fst <$> x) [para . snd <$> x]
111
106
112generateReport :: ReportConfig -> ReportInput -> (Blocks, ReportStatus)
107generateReport :: ReportConfig -> ReportInput -> (Blocks, ReportStatus)
113generateReport cfg inp =
108generateReport cfg inp =
109+ let
114− let schemaIssuesPresent = not $ P.null $ schemaIssues inp
110+ schemaIssuesPresent = not $ P.null $ schemaIssues inp
115 breakingChangesPresent = not $ P.null $ breakingChanges inp
111 breakingChangesPresent = not $ P.null $ breakingChanges inp
116 nonBreakingChangesPresent = not $ P.null $ nonBreakingChanges inp
112 nonBreakingChangesPresent = not $ P.null $ nonBreakingChanges inp
117 unsupportedChangesPresent = not $ P.null $ unsupportedChanges inp
113 unsupportedChangesPresent = not $ P.null $ unsupportedChanges inp
@@ -120,55 +116,47 @@ generateReport cfg inp =
120 OnlyErrors -> False
116 OnlyErrors -> False
121 builder = buildReport cfg
117 builder = buildReport cfg
122 report =
118 report =
123− header 1 "Summary"
119+ header 1 "Summary"
124− <> twoRowTable
120+ <> twoRowTable
125− ( when'
121+ (when'
126− schemaIssuesPresent
122+ schemaIssuesPresent
127− [
128− ( refOpt schemaIssuesPresent schemaIssuesId "‼️ Schema issues"
123+ [ ( refOpt schemaIssuesPresent schemaIssuesId "‼️ Schema issues"
129− , show' $ P.size $ schemaIssues inp
124+ , show' $ P.size $ schemaIssues inp
130− )
125+ )
131− ]
126+ ]
132− ++ [
127+ ++
133− ( refOpt breakingChangesPresent breakingChangesId "❌ Breaking changes"
128+ [ ( refOpt breakingChangesPresent breakingChangesId "❌ Breaking changes"
134 , show' $ P.size $ breakingChanges inp
129 , show' $ P.size $ breakingChanges inp
135 )
130 )
136 ]
131 ]
137− ++ when'
132+ ++ when'
138− nonBreakingChangesShown
133+ nonBreakingChangesShown
139− [
140− ( refOpt nonBreakingChangesPresent nonBreakingChangesId "⚠️ Non-breaking changes"
134+ [ ( refOpt nonBreakingChangesPresent nonBreakingChangesId "⚠️ Non-breaking changes"
141− , show' $ P.size $ nonBreakingChanges inp
135+ , show' $ P.size $ nonBreakingChanges inp
142− )
136+ )
143− ]
137+ ]
144− ++ when'
138+ ++ when'
145− unsupportedChangesPresent
139+ unsupportedChangesPresent
146− [
147− ( refOpt unsupportedChangesPresent unsupportedChangesId "❓ Unsupported feature changes"
140+ [ ( refOpt unsupportedChangesPresent unsupportedChangesId "❓ Unsupported feature changes"
148− , show' $ P.size $ unsupportedChanges inp
141+ , show' $ P.size $ unsupportedChanges inp
149− )
142+ )
150− ]
143+ ])
151− )
152− <> when'
144+ <> when'
153− schemaIssuesPresent
145+ schemaIssuesPresent
154− ( header 1 (anchor schemaIssuesId <> "‼️ Schema issues")
146+ (header 1 (anchor schemaIssuesId <> "‼️ Schema issues")
155− <> builder (showErrs $ schemaIssues inp)
147+ <> builder (showErrs $ schemaIssues inp))
156− )
157− <> when'
148+ <> when'
158− breakingChangesPresent
149+ breakingChangesPresent
159− ( header 1 (anchor breakingChangesId <> "❌ Breaking changes")
150+ (header 1 (anchor breakingChangesId <> "❌ Breaking changes")
160− <> builder (showErrs $ breakingChanges inp)
151+ <> builder (showErrs $ breakingChanges inp))
161− )
162− <> when'
152+ <> when'
163− (nonBreakingChangesPresent && nonBreakingChangesShown)
153+ (nonBreakingChangesPresent && nonBreakingChangesShown)
164− ( header 1 (anchor nonBreakingChangesId <> "⚠️ Non-breaking changes")
154+ (header 1 (anchor nonBreakingChangesId <> "⚠️ Non-breaking changes")
165− <> builder (showErrs $ nonBreakingChanges inp)
155+ <> builder (showErrs $ nonBreakingChanges inp))
166− )
167− <> when'
156+ <> when'
168− unsupportedChangesPresent
157+ unsupportedChangesPresent
169− ( header 1 (anchor unsupportedChangesId <> "❓ Unsupported feature changes")
158+ (header 1 (anchor unsupportedChangesId <> "❓ Unsupported feature changes")
170− <> builder (showErrs $ unsupportedChanges inp)
159+ <> builder (showErrs $ unsupportedChanges inp))
171− )
172 status =
160 status =
173 if
161 if
174 | breakingChangesPresent -> BreakingChanges
162 | breakingChangesPresent -> BreakingChanges
@@ -198,14 +186,13 @@ showErrs x@(P.PathsPrefixNode currentIssues _) =
198 let -- Extract this pattern if more cases like this arise
186 let -- Extract this pattern if more cases like this arise
199 ( removedPaths :: Maybe (Orientation, [Issue 'APILevel])
187 ( removedPaths :: Maybe (Orientation, [Issue 'APILevel])
200 , otherIssues :: Set (AnIssue a)
188 , otherIssues :: Set (AnIssue a)
201− ) = case eqT @a @ 'APILevel of
189+ ) = case eqT @a @'APILevel of
202 Just Refl
190 Just Refl
203 | (S.toList -> p@((AnIssue ori _) : _), o) <-
191 | (S.toList -> p@((AnIssue ori _) : _), o) <-
204 S.partition
192 S.partition
205− ( \((AnIssue _ u)) -> case u of
193+ (\((AnIssue _ u)) -> case u of
206− NoPathsMatched {} -> True
194+ NoPathsMatched {} -> True
207− AllPathsFailed {} -> True
195+ AllPathsFailed {} -> True)
208− )
209 currentIssues ->
196 currentIssues ->
210 let p' = p <&> (\(AnIssue _ i) -> i)
197 let p' = p <&> (\(AnIssue _ i) -> i)
211 in (Just (ori, p'), o)
198 in (Just (ori, p'), o)
@@ -216,10 +203,9 @@ showErrs x@(P.PathsPrefixNode currentIssues _) =
216 paths = case removedPaths of
203 paths = case removedPaths of
217 Just (ori, ps) -> do
204 Just (ori, ps) -> do
218 singletonHeader
205 singletonHeader
219− ( case ori of
206+ (case ori of
220− Forward -> "Removed paths"
207+ Forward -> "Removed paths"
221− Backward -> "Added paths"
208+ Backward -> "Added paths")
222− )
223 $ singletonBody $
209 $ singletonBody $
224 bulletList $
210 bulletList $
225 ps <&> \case
211 ps <&> \case
@@ -263,54 +249,52 @@ jets =
263 unwrapReportJetResult (Pure _) = error "There really shouldn't be any results here."
249 unwrapReportJetResult (Pure _) = error "There really shouldn't be any results here."
264 unwrapReportJetResult (Free f) = f
250 unwrapReportJetResult (Free f) = f
265
251
266− jsonPathJet ::
252+ jsonPathJet
267− NonEmpty
253+ :: NonEmpty
268− ( Union
254+ ( Union
269− '[ Behave 'SchemaLevel 'TypedSchemaLevel
255+ '[ Behave 'SchemaLevel 'TypedSchemaLevel
270− , Behave 'TypedSchemaLevel 'SchemaLevel
256+ , Behave 'TypedSchemaLevel 'SchemaLevel
271− ]
257+ ]
272− ) ->
258+ )
273− Inlines
259+ -> Inlines
274 jsonPathJet x = code $ "$" <> showParts (NE.toList x)
260 jsonPathJet x = code $ "$" <> showParts (NE.toList x)
275 where
261 where
276− showParts ::
262+ showParts
277− [ Union
263+ :: [ Union
278− '[ Behave 'SchemaLevel 'TypedSchemaLevel
264+ '[ Behave 'SchemaLevel 'TypedSchemaLevel
279− , Behave 'TypedSchemaLevel 'SchemaLevel
265+ , Behave 'TypedSchemaLevel 'SchemaLevel
280− ]
266+ ]
281− ] ->
267+ ]
282− Text
268+ -> Text
283 showParts [] = mempty
269 showParts [] = mempty
284 showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion (InProperty _)) : _)) = showParts xs
270 showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion (InProperty _)) : _)) = showParts xs
285 showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion InAdditionalProperty) : _)) = showParts xs
271 showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion InAdditionalProperty) : _)) = showParts xs
286 showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion InItems : _)) = showParts xs
272 showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion InItems : _)) = showParts xs
287 showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion (InItem _) : _)) = showParts xs
273 showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion (InItem _) : _)) = showParts xs
288 showParts (y : ys) =
274 showParts (y : ys) =
289− ( (\(OfType t) -> "(" <> describeJSONType t <> ")")
275+ ((\(OfType t) -> "(" <> describeJSONType t <> ")")
290− @@> ( \case
276+ @@> (\case
291− InItems -> "[*]"
277+ InItems -> "[*]"
292− InItem i -> "[" <> T.pack (show i) <> "]"
278+ InItem i -> "[" <> T.pack (show i) <> "]"
293− InProperty p -> "." <> p
279+ InProperty p -> "." <> p
294− InAdditionalProperty -> ".*"
280+ InAdditionalProperty -> ".*")
295− )
296− @@> typesExhausted
281+ @@> typesExhausted)
297− )
298 y
282 y
299 <> showParts ys
283 <> showParts ys
300
284
301−observeJetShowErrs ::
285+observeJetShowErrs
302− ReportJet' Behave (Maybe Inlines) ->
286+ :: ReportJet' Behave (Maybe Inlines)
303− P.PathsPrefixTree Behave AnIssue a ->
287+ -> P.PathsPrefixTree Behave AnIssue a
304− (Report, P.PathsPrefixTree Behave AnIssue a)
288+ -> (Report, P.PathsPrefixTree Behave AnIssue a)
305observeJetShowErrs jet p = case observeJetShowErrs' jet p of
289observeJetShowErrs jet p = case observeJetShowErrs' jet p of
306 Just m -> m
290 Just m -> m
307 Nothing -> (mempty, p)
291 Nothing -> (mempty, p)
308
292
309−observeJetShowErrs' ::
293+observeJetShowErrs'
310− forall a.
294+ :: forall a.
311− ReportJet' Behave (Maybe Inlines) ->
295+ ReportJet' Behave (Maybe Inlines)
312− P.PathsPrefixTree Behave AnIssue a ->
296+ -> P.PathsPrefixTree Behave AnIssue a
313− Maybe (Report, P.PathsPrefixTree Behave AnIssue a)
297+ -> Maybe (Report, P.PathsPrefixTree Behave AnIssue a)
314observeJetShowErrs' (ReportJet jet) (P.PathsPrefixNode currentIssues subIssues) =
298observeJetShowErrs' (ReportJet jet) (P.PathsPrefixNode currentIssues subIssues) =
315 let results =
299 let results =
316 subIssues >>= \(WrapTypeable (AStep m)) ->
300 subIssues >>= \(WrapTypeable (AStep m)) ->
@@ -318,23 +302,21 @@ observeJetShowErrs' (ReportJet jet) (P.PathsPrefixNode currentIssues subIssues)
318 maybe (Left $ embed (step bhv) subErrs) Right . listToMaybe $
302 maybe (Left $ embed (step bhv) subErrs) Right . listToMaybe $
319 jet @_ @_ @[] bhv
303 jet @_ @_ @[] bhv
320 & mapMaybe
304 & mapMaybe
321− ( \case
305+ (\case
322− Free jet' -> fmap (embed $ step bhv) <$> observeJetShowErrs' jet' subErrs
306+ Free jet' -> fmap (embed $ step bhv) <$> observeJetShowErrs' jet' subErrs
323− Pure (Just h) ->
307+ Pure (Just h) ->
324− if P.null subErrs
308+ if P.null subErrs
325− then Just mempty
309+ then Just mempty
326− else Just (singletonHeader h (showErrs subErrs), mempty)
310+ else Just (singletonHeader h (showErrs subErrs), mempty)
327− Pure Nothing -> Nothing
311+ Pure Nothing -> Nothing)
328− )
329 in (fmap . fmap) (PathsPrefixNode currentIssues mempty <>) $
312 in (fmap . fmap) (PathsPrefixNode currentIssues mempty <>) $
330 if any isRight results
313 if any isRight results
331 then
314 then
332 Just $
315 Just $
333 foldMap
316 foldMap
334− ( \case
317+ (\case
335− Left e -> (mempty, e)
318+ Left e -> (mempty, e)
336− Right m -> m
319+ Right m -> m)
337− )
338 results
320 results
339 else Nothing
321 else Nothing
340
322
@@ -357,9 +339,8 @@ buildReport cfg = case treeStyle cfg of
357 body rprt
339 body rprt
358 <> foldOMapWithKey
340 <> foldOMapWithKey
359 (headers rprt)
341 (headers rprt)
360− ( \k v ->
342+ (\k v ->
361− header level k <> subBuilder v
343+ header level k <> subBuilder v)
362− )
363 where
344 where
364 subBuilder = headerStyleBuilder (level + 1)
345 subBuilder = headerStyleBuilder (level + 1)
365
346
@@ -368,17 +349,16 @@ buildReport cfg = case treeStyle cfg of
368 body rprt
349 body rprt
369 <> foldOMapWithKey
350 <> foldOMapWithKey
370 (headers rprt)
351 (headers rprt)
371− ( \k v ->
352+ (\k v ->
372− if (OM.size . headers $ rprt) < 2
353+ if (OM.size . headers $ rprt) < 2
373− then para k <> blockQuote (subBuilder v)
354+ then para k <> blockQuote (subBuilder v)
374− else
355+ else
375− rawHtml "<details>"
356+ rawHtml "<details>"
376− <> rawHtml "<summary>"
357+ <> rawHtml "<summary>"
377− <> plain k
358+ <> plain k
378− <> rawHtml "</summary>"
359+ <> rawHtml "</summary>"
379− <> blockQuote (subBuilder v)
360+ <> blockQuote (subBuilder v)
380− <> rawHtml "</details>"
361+ <> rawHtml "</details>")
381− )
382 where
362 where
383 subBuilder = foldingStyleBuilder
363 subBuilder = foldingStyleBuilder
384
364
src/Data/OpenApi/Compare/Report/Html/Template.hs+1−1
@@ -1,7 +1,7 @@
1{-# LANGUAGE TemplateHaskell #-}
1{-# LANGUAGE TemplateHaskell #-}
2
2
3module Data.OpenApi.Compare.Report.Html.Template
3module Data.OpenApi.Compare.Report.Html.Template
4− ( template,
4+ ( template
5 )
5 )
6where
6where
7
7
src/Data/OpenApi/Compare/Report/Jet.hs+4−4
@@ -1,8 +1,8 @@
1module Data.OpenApi.Compare.Report.Jet
1module Data.OpenApi.Compare.Report.Jet
2− ( ReportJet (..),
2+ ( ReportJet (..)
3− ReportJet',
3+ , ReportJet'
4− ConstructReportJet (..),
4+ , ConstructReportJet (..)
5− ReportJetResult,
5+ , ReportJetResult
6 )
6 )
7where
7where
8
8
src/Data/OpenApi/Compare/Run.hs+4−4
@@ -1,17 +1,17 @@
1module Data.OpenApi.Compare.Run
1module Data.OpenApi.Compare.Run
2− ( runChecker,
2+ ( runChecker
3− runReport,
3+ , runReport
4− module Data.OpenApi.Compare.Report,
4+ , module Data.OpenApi.Compare.Report
5 )
5 )
6where
6where
7
7
8import Data.HList
8import Data.HList
9import Data.OpenApi (OpenApi)
9import Data.OpenApi (OpenApi)
10+import Text.Pandoc.Builder
10import Data.OpenApi.Compare.Paths
11import Data.OpenApi.Compare.Paths
11import Data.OpenApi.Compare.Report
12import Data.OpenApi.Compare.Report
12import Data.OpenApi.Compare.Subtree
13import Data.OpenApi.Compare.Subtree
13import Data.OpenApi.Compare.Validate.OpenApi ()
14import Data.OpenApi.Compare.Validate.OpenApi ()
14−import Text.Pandoc.Builder
15
15
16runChecker :: (OpenApi, OpenApi) -> CheckerOutput
16runChecker :: (OpenApi, OpenApi) -> CheckerOutput
17runChecker (client, server) =
17runChecker (client, server) =
src/Data/OpenApi/Compare/Subtree.hs+120−122
@@ -1,52 +1,52 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2
2
3module Data.OpenApi.Compare.Subtree
3module Data.OpenApi.Compare.Subtree
4− ( Steppable (..),
4+ ( Steppable (..)
5− Step (..),
5+ , Step (..)
6− TraceRoot,
6+ , TraceRoot
7− Trace,
7+ , Trace
8− Traced,
8+ , Traced
9− Traced',
9+ , Traced'
10− pattern Traced,
10+ , pattern Traced
11− traced,
11+ , traced
12− retraced,
12+ , retraced
13− stepTraced,
13+ , stepTraced
14− Subtree (..),
14+ , Subtree (..)
15− checkCompatibility,
15+ , checkCompatibility
16− checkSubstructure,
16+ , checkSubstructure
17− CompatM (..),
17+ , CompatM (..)
18− CompatFormula',
18+ , CompatFormula'
19− SemanticCompatFormula,
19+ , SemanticCompatFormula
20− ProdCons (..),
20+ , ProdCons (..)
21− orientProdCons,
21+ , orientProdCons
22− swapProdCons,
22+ , swapProdCons
23− runCompatFormula,
23+ , runCompatFormula
24− issueAt,
24+ , issueAt
25− anItem,
25+ , anItem
26− anIssue,
26+ , anIssue
27− invertIssueOrientation,
27+ , invertIssueOrientation
28− invertIssueOrientationP,
28+ , invertIssueOrientationP
29− embedFormula,
29+ , embedFormula
30− anyOfAt,
30+ , anyOfAt
31− clarifyIssue,
31+ , clarifyIssue
32− structuralIssue,
32+ , structuralIssue
33
33
34 -- * Structural helpers
34 -- * Structural helpers
35− structuralMaybe,
35+ , structuralMaybe
36− structuralMaybeWith,
36+ , structuralMaybeWith
37− structuralEq,
37+ , structuralEq
38− iohmStructural,
38+ , iohmStructural
39− iohmStructuralWith,
39+ , iohmStructuralWith
40− structuralList,
40+ , structuralList
41
41
42 -- * Reexports
42 -- * Reexports
43− (>>>),
43+ , (>>>)
44− (<<<),
44+ , (<<<)
45− extract,
45+ , extract
46− ask,
46+ , ask
47− local,
47+ , local
48− step,
48+ , step
49− Typeable,
49+ , Typeable
50 )
50 )
51where
51where
52
52
@@ -115,10 +115,10 @@ orientProdCons :: Orientation -> ProdCons x -> ProdCons x
115orientProdCons Forward x = x
115orientProdCons Forward x = x
116orientProdCons Backward (ProdCons p c) = ProdCons c p
116orientProdCons Backward (ProdCons p c) = ProdCons c p
117
117
118−swapProdCons ::
118+swapProdCons
119− SwapEnvRoles xs =>
119+ :: SwapEnvRoles xs
120− (HList xs -> ProdCons x -> CompatFormula' q AnIssue r a) ->
120+ => (HList xs -> ProdCons x -> CompatFormula' q AnIssue r a)
121− (HList xs -> ProdCons x -> CompatFormula' q AnIssue r a)
121+ -> (HList xs -> ProdCons x -> CompatFormula' q AnIssue r a)
122swapProdCons f e (ProdCons p c) =
122swapProdCons f e (ProdCons p c) =
123 invertIssueOrientation $
123 invertIssueOrientation $
124 f (swapEnvRoles e) (ProdCons c p)
124 f (swapEnvRoles e) (ProdCons c p)
@@ -153,8 +153,8 @@ instance Applicative ProdCons where
153 ProdCons fp fc <*> ProdCons xp xc = ProdCons (fp xp) (fc xc)
153 ProdCons fp fc <*> ProdCons xp xc = ProdCons (fp xp) (fc xc)
154
154
155newtype CompatM a = CompatM
155newtype CompatM a = CompatM
156− { unCompatM ::
156+ { unCompatM
157− StateT (MemoState VarRef) Identity a
157+ :: StateT (MemoState VarRef) Identity a
158 }
158 }
159 deriving newtype
159 deriving newtype
160 ( Functor
160 ( Functor
@@ -183,64 +183,64 @@ class (Typeable t, Issuable (SubtreeLevel t)) => Subtree (t :: Type) where
183 type CheckEnv t :: [Type]
183 type CheckEnv t :: [Type]
184 type SubtreeLevel t :: BehaviorLevel
184 type SubtreeLevel t :: BehaviorLevel
185
185
186− checkStructuralCompatibility ::
186+ checkStructuralCompatibility
187− HList (CheckEnv t) ->
187+ :: HList (CheckEnv t)
188− ProdCons (Traced t) ->
188+ -> ProdCons (Traced t)
189− StructuralCompatFormula ()
189+ -> StructuralCompatFormula ()
190
190
191− checkSemanticCompatibility ::
191+ checkSemanticCompatibility
192− HList (CheckEnv t) ->
192+ :: HList (CheckEnv t)
193− Behavior (SubtreeLevel t) ->
193+ -> Behavior (SubtreeLevel t)
194− ProdCons (Traced t) ->
194+ -> ProdCons (Traced t)
195− SemanticCompatFormula ()
195+ -> SemanticCompatFormula ()
196
196
197{-# WARNING checkStructuralCompatibility "You should not be calling this directly. Use 'checkSubstructure'" #-}
197{-# WARNING checkStructuralCompatibility "You should not be calling this directly. Use 'checkSubstructure'" #-}
198
198
199{-# WARNING checkSemanticCompatibility "You should not be calling this directly. Use 'checkCompatibility'" #-}
199{-# WARNING checkSemanticCompatibility "You should not be calling this directly. Use 'checkCompatibility'" #-}
200
200
201−checkCompatibility ::
201+checkCompatibility
202− forall t xs.
202+ :: forall t xs.
203− (ReassembleHList xs (CheckEnv t), Subtree t) =>
203+ (ReassembleHList xs (CheckEnv t), Subtree t)
204− Behavior (SubtreeLevel t) ->
204+ => Behavior (SubtreeLevel t)
205− HList xs ->
205+ -> HList xs
206− ProdCons (Traced t) ->
206+ -> ProdCons (Traced t)
207− SemanticCompatFormula ()
207+ -> SemanticCompatFormula ()
208checkCompatibility bhv e = memo bhv SemanticMemoKey $ \pc ->
208checkCompatibility bhv e = memo bhv SemanticMemoKey $ \pc ->
209 case runCompatFormula $ checkSubstructure e pc of
209 case runCompatFormula $ checkSubstructure e pc of
210 Left _ -> checkSemanticCompatibility (reassemble e) bhv pc
210 Left _ -> checkSemanticCompatibility (reassemble e) bhv pc
211 Right () -> pure ()
211 Right () -> pure ()
212{-# INLINE checkCompatibility #-}
212{-# INLINE checkCompatibility #-}
213
213
214−checkSubstructure ::
214+checkSubstructure
215− (ReassembleHList xs (CheckEnv t), Subtree t) =>
215+ :: (ReassembleHList xs (CheckEnv t), Subtree t)
216− HList xs ->
216+ => HList xs
217− ProdCons (Traced t) ->
217+ -> ProdCons (Traced t)
218− StructuralCompatFormula ()
218+ -> StructuralCompatFormula ()
219checkSubstructure e = memo Root StructuralMemoKey $ checkStructuralCompatibility (reassemble e)
219checkSubstructure e = memo Root StructuralMemoKey $ checkStructuralCompatibility (reassemble e)
220{-# INLINE checkSubstructure #-}
220{-# INLINE checkSubstructure #-}
221
221
222−structuralMaybe ::
222+structuralMaybe
223− (Subtree a, ReassembleHList xs (CheckEnv a)) =>
223+ :: (Subtree a, ReassembleHList xs (CheckEnv a))
224− HList xs ->
224+ => HList xs
225− ProdCons (Maybe (Traced a)) ->
225+ -> ProdCons (Maybe (Traced a))
226− StructuralCompatFormula ()
226+ -> StructuralCompatFormula ()
227structuralMaybe e = structuralMaybeWith (checkSubstructure e)
227structuralMaybe e = structuralMaybeWith (checkSubstructure e)
228{-# INLINE structuralMaybe #-}
228{-# INLINE structuralMaybe #-}
229
229
230−structuralMaybeWith ::
230+structuralMaybeWith
231− (ProdCons a -> StructuralCompatFormula ()) ->
231+ :: (ProdCons a -> StructuralCompatFormula ())
232− ProdCons (Maybe a) ->
232+ -> ProdCons (Maybe a)
233− StructuralCompatFormula ()
233+ -> StructuralCompatFormula ()
234structuralMaybeWith f (ProdCons (Just a) (Just b)) = f $ ProdCons a b
234structuralMaybeWith f (ProdCons (Just a) (Just b)) = f $ ProdCons a b
235structuralMaybeWith _ (ProdCons Nothing Nothing) = pure ()
235structuralMaybeWith _ (ProdCons Nothing Nothing) = pure ()
236structuralMaybeWith _ _ = structuralIssue
236structuralMaybeWith _ _ = structuralIssue
237{-# INLINE structuralMaybeWith #-}
237{-# INLINE structuralMaybeWith #-}
238
238
239−structuralList ::
239+structuralList
240− (Subtree a, ReassembleHList xs (CheckEnv a)) =>
240+ :: (Subtree a, ReassembleHList xs (CheckEnv a))
241− HList xs ->
241+ => HList xs
242− ProdCons [Traced a] ->
242+ -> ProdCons [Traced a]
243− StructuralCompatFormula ()
243+ -> StructuralCompatFormula ()
244structuralList _ (ProdCons [] []) = pure ()
244structuralList _ (ProdCons [] []) = pure ()
245structuralList e (ProdCons (a : aa) (b : bb)) = do
245structuralList e (ProdCons (a : aa) (b : bb)) = do
246 checkSubstructure e $ ProdCons a b
246 checkSubstructure e $ ProdCons a b
@@ -253,11 +253,11 @@ structuralEq :: (Eq a, Comonad w) => ProdCons (w a) -> StructuralCompatFormula (
253structuralEq (ProdCons a b) = if extract a == extract b then pure () else structuralIssue
253structuralEq (ProdCons a b) = if extract a == extract b then pure () else structuralIssue
254{-# INLINE structuralEq #-}
254{-# INLINE structuralEq #-}
255
255
256−iohmStructural ::
256+iohmStructural
257− (ReassembleHList (k ': xs) (CheckEnv v), Ord k, Subtree v, Hashable k, Typeable k, Show k) =>
257+ :: (ReassembleHList (k ': xs) (CheckEnv v), Ord k, Subtree v, Hashable k, Typeable k, Show k)
258− HList xs ->
258+ => HList xs
259− ProdCons (Traced (IOHM.InsOrdHashMap k v)) ->
259+ -> ProdCons (Traced (IOHM.InsOrdHashMap k v))
260− StructuralCompatFormula ()
260+ -> StructuralCompatFormula ()
261iohmStructural e =
261iohmStructural e =
262 iohmStructuralWith (\k -> checkSubstructure (k `HCons` e))
262 iohmStructuralWith (\k -> checkSubstructure (k `HCons` e))
263{-# INLINE iohmStructural #-}
263{-# INLINE iohmStructural #-}
@@ -266,26 +266,25 @@ instance (Typeable k, Typeable v, Ord k, Show k) => Steppable (IOHM.InsOrdHashMa
266 data Step (IOHM.InsOrdHashMap k v) v = InsOrdHashMapKeyStep k
266 data Step (IOHM.InsOrdHashMap k v) v = InsOrdHashMapKeyStep k
267 deriving stock (Eq, Ord, Show)
267 deriving stock (Eq, Ord, Show)
268
268
269−iohmStructuralWith ::
269+iohmStructuralWith
270− (Ord k, Hashable k, Typeable k, Typeable v, Show k) =>
270+ :: (Ord k, Hashable k, Typeable k, Typeable v, Show k)
271− (k -> ProdCons (Traced v) -> StructuralCompatFormula ()) ->
271+ => (k -> ProdCons (Traced v) -> StructuralCompatFormula ())
272− ProdCons (Traced (IOHM.InsOrdHashMap k v)) ->
272+ -> ProdCons (Traced (IOHM.InsOrdHashMap k v))
273− StructuralCompatFormula ()
273+ -> StructuralCompatFormula ()
274iohmStructuralWith f pc = do
274iohmStructuralWith f pc = do
275 let ProdCons pEKeys cEKeys = S.fromList . IOHM.keys . extract <$> pc
275 let ProdCons pEKeys cEKeys = S.fromList . IOHM.keys . extract <$> pc
276 if pEKeys == cEKeys
276 if pEKeys == cEKeys
277 then
277 then
278 for_
278 for_
279 pEKeys
279 pEKeys
280− ( \eKey ->
280+ (\eKey ->
281− f eKey $ stepTraced (InsOrdHashMapKeyStep eKey) . fmap (IOHM.lookupDefault (error "impossible") eKey) <$> pc
281+ f eKey $ stepTraced (InsOrdHashMapKeyStep eKey) . fmap (IOHM.lookupDefault (error "impossible") eKey) <$> pc)
282− )
283 else structuralIssue
282 else structuralIssue
284{-# INLINE iohmStructuralWith #-}
283{-# INLINE iohmStructuralWith #-}
285
284
286−runCompatFormula ::
285+runCompatFormula
287− CompatFormula' q f r a ->
286+ :: CompatFormula' q f r a
288− Either (P.PathsPrefixTree q f r) a
287+ -> Either (P.PathsPrefixTree q f r) a
289runCompatFormula (Compose f) =
288runCompatFormula (Compose f) =
290 calculate . runIdentity . runMemo 0 . unCompatM $ f
289 calculate . runIdentity . runMemo 0 . unCompatM $ f
291{-# INLINE runCompatFormula #-}
290{-# INLINE runCompatFormula #-}
@@ -315,27 +314,27 @@ invertIssueOrientationP = P.map (\(AnIssue ori i) -> AnIssue (toggleOrientation
315structuralIssue :: StructuralCompatFormula a
314structuralIssue :: StructuralCompatFormula a
316structuralIssue = Compose $ pure $ anError $ AnItem Root Proxy
315structuralIssue = Compose $ pure $ anError $ AnItem Root Proxy
317
316
318−anyOfAt ::
317+anyOfAt
319− Issuable l =>
318+ :: Issuable l
320− Paths q r l ->
319+ => Paths q r l
321− Issue l ->
320+ -> Issue l
322− [CompatFormula' q AnIssue r a] ->
321+ -> [CompatFormula' q AnIssue r a]
323− CompatFormula' q AnIssue r a
322+ -> CompatFormula' q AnIssue r a
324anyOfAt _ _ [x] = x
323anyOfAt _ _ [x] = x
325anyOfAt xs issue fs =
324anyOfAt xs issue fs =
326 Compose $ (`eitherOf` AnItem xs (anIssue issue)) <$> traverse getCompose fs
325 Compose $ (`eitherOf` AnItem xs (anIssue issue)) <$> traverse getCompose fs
327
326
328-- | If the given formula contains any issues, add another issue on top. Otherwise succeed.
327-- | If the given formula contains any issues, add another issue on top. Otherwise succeed.
329−clarifyIssue ::
328+clarifyIssue
330− AnItem q AnIssue r ->
329+ :: AnItem q AnIssue r
331− CompatFormula' q AnIssue r a ->
330+ -> CompatFormula' q AnIssue r a
332− CompatFormula' q AnIssue r a
331+ -> CompatFormula' q AnIssue r a
333clarifyIssue item f =
332clarifyIssue item f =
334 Compose ((`eitherOf` item) <$> pure <$> getCompose f) *> f
333 Compose ((`eitherOf` item) <$> pure <$> getCompose f) *> f
335
334
336−fixpointKnot ::
335+fixpointKnot
337− MonadState (MemoState VarRef) m =>
336+ :: MonadState (MemoState VarRef) m
338− KnotTier (FormulaF q f r ()) VarRef m
337+ => KnotTier (FormulaF q f r ()) VarRef m
339fixpointKnot =
338fixpointKnot =
340 KnotTier
339 KnotTier
341 { onKnotFound = modifyMemoNonce succ
340 { onKnotFound = modifyMemoNonce succ
@@ -343,20 +342,19 @@ fixpointKnot =
343 , tieKnot = \i x -> pure $ maxFixpoint i x
342 , tieKnot = \i x -> pure $ maxFixpoint i x
344 }
343 }
345
344
346−memo ::
345+memo
347− (Typeable (l :: k), Typeable q, Typeable f, Typeable k, Typeable a) =>
346+ :: (Typeable (l :: k), Typeable q, Typeable f, Typeable k, Typeable a)
348− Paths q r l ->
347+ => Paths q r l
349− MemoKey ->
348+ -> MemoKey
350− (ProdCons (Traced a) -> CompatFormula' q f r ()) ->
349+ -> (ProdCons (Traced a) -> CompatFormula' q f r ())
351− (ProdCons (Traced a) -> CompatFormula' q f r ())
350+ -> (ProdCons (Traced a) -> CompatFormula' q f r ())
352memo bhv k f pc = Compose $ do
351memo bhv k f pc = Compose $ do
353 formula' <-
352 formula' <-
354 memoWithKnot
353 memoWithKnot
355 fixpointKnot
354 fixpointKnot
356− ( do
355+ (do
357− formula <- getCompose $ f pc
356+ formula <- getCompose $ f pc
358− pure $ mapErrors (P.takeSubtree bhv) formula
357+ pure $ mapErrors (P.takeSubtree bhv) formula)
359− )
360 (k, ask <$> pc)
358 (k, ask <$> pc)
361 pure $ mapErrors (P.embed bhv) formula'
359 pure $ mapErrors (P.embed bhv) formula'
362
360
src/Data/OpenApi/Compare/Validate/MediaTypeObject.hs+2−2
@@ -1,8 +1,8 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2
2
3module Data.OpenApi.Compare.Validate.MediaTypeObject
3module Data.OpenApi.Compare.Validate.MediaTypeObject
4− ( Issue (..),
4+ ( Issue (..)
5− Behave (..),
5+ , Behave (..)
6 )
6 )
7where
7where
8
8
src/Data/OpenApi/Compare/Validate/OAuth2Flows.hs+13−13
@@ -1,9 +1,9 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2
2
3module Data.OpenApi.Compare.Validate.OAuth2Flows
3module Data.OpenApi.Compare.Validate.OAuth2Flows
4− ( Step (..),
4+ ( Step (..)
5− Issue (..),
5+ , Issue (..)
6− Behave (..),
6+ , Behave (..)
7 )
7 )
8where
8where
9
9
@@ -26,11 +26,11 @@ instance Subtree OAuth2Flows where
26 type SubtreeLevel OAuth2Flows = 'SecuritySchemeLevel
26 type SubtreeLevel OAuth2Flows = 'SecuritySchemeLevel
27 checkStructuralCompatibility _ = structuralEq
27 checkStructuralCompatibility _ = structuralEq
28 checkSemanticCompatibility env bhv pc = do
28 checkSemanticCompatibility env bhv pc = do
29− let supportFlow ::
29+ let supportFlow
30− (Subtree t, SubtreeLevel t ~ SubtreeLevel OAuth2Flows, CheckEnv OAuth2Flows ~ CheckEnv t) =>
30+ :: (Subtree t, SubtreeLevel t ~ SubtreeLevel OAuth2Flows, CheckEnv OAuth2Flows ~ CheckEnv t)
31− Issue 'SecuritySchemeLevel ->
31+ => Issue 'SecuritySchemeLevel
32− ProdCons (Maybe (Traced t)) ->
32+ -> ProdCons (Maybe (Traced t))
33− SemanticCompatFormula ()
33+ -> SemanticCompatFormula ()
34 supportFlow i x = case x of
34 supportFlow i x = case x of
35 -- producer will not attempt this flow
35 -- producer will not attempt this flow
36 (ProdCons Nothing _) -> pure ()
36 (ProdCons Nothing _) -> pure ()
@@ -38,11 +38,11 @@ instance Subtree OAuth2Flows where
38 (ProdCons (Just _) Nothing) -> issueAt bhv i
38 (ProdCons (Just _) Nothing) -> issueAt bhv i
39 (ProdCons (Just p) (Just c)) ->
39 (ProdCons (Just p) (Just c)) ->
40 checkCompatibility bhv env $ ProdCons p c
40 checkCompatibility bhv env $ ProdCons p c
41− getFlow ::
41+ getFlow
42− Typeable x =>
42+ :: Typeable x
43− (OAuth2Flows -> Maybe (OAuth2Flow x)) ->
43+ => (OAuth2Flows -> Maybe (OAuth2Flow x))
44− Traced OAuth2Flows ->
44+ -> Traced OAuth2Flows
45− Maybe (Traced (OAuth2Flow x))
45+ -> Maybe (Traced (OAuth2Flow x))
46 getFlow f (Traced t a) = Traced (t >>> step (OAuth2FlowsFlow Proxy)) <$> f a
46 getFlow f (Traced t a) = Traced (t >>> step (OAuth2FlowsFlow Proxy)) <$> f a
47 supportFlow ConsumerDoesNotSupportImplicitFlow $ getFlow _oAuth2FlowsImplicit <$> pc
47 supportFlow ConsumerDoesNotSupportImplicitFlow $ getFlow _oAuth2FlowsImplicit <$> pc
48 supportFlow ConsumerDoesNotSupportPasswordFlow $ getFlow _oAuth2FlowsPassword <$> pc
48 supportFlow ConsumerDoesNotSupportPasswordFlow $ getFlow _oAuth2FlowsPassword <$> pc
src/Data/OpenApi/Compare/Validate/OpenApi.hs+12−13
@@ -3,8 +3,8 @@
3{-# OPTIONS_GHC -fconstraint-solver-iterations=0 #-}
3{-# OPTIONS_GHC -fconstraint-solver-iterations=0 #-}
4
4
5module Data.OpenApi.Compare.Validate.OpenApi
5module Data.OpenApi.Compare.Validate.OpenApi
6− ( Behave (..),
6+ ( Behave (..)
7− Issue (..),
7+ , Issue (..)
8 )
8 )
9where
9where
10
10
@@ -79,17 +79,16 @@ instance Subtree OpenApi where
79 checkSemanticCompatibility _ beh prodCons = do
79 checkSemanticCompatibility _ beh prodCons = do
80 checkCompatibility @ProcessedPathItems
80 checkCompatibility @ProcessedPathItems
81 beh
81 beh
82− ( (tracedRequestBodies <$> prodCons)
82+ ((tracedRequestBodies <$> prodCons)
83− `HCons` (tracedParameters <$> prodCons)
83+ `HCons` (tracedParameters <$> prodCons)
84− `HCons` (tracedSecuritySchemes <$> prodCons)
84+ `HCons` (tracedSecuritySchemes <$> prodCons)
85− `HCons` (tracedResponses <$> prodCons)
85+ `HCons` (tracedResponses <$> prodCons)
86− `HCons` (tracedHeaders <$> prodCons)
86+ `HCons` (tracedHeaders <$> prodCons)
87− `HCons` (tracedSchemas <$> prodCons)
87+ `HCons` (tracedSchemas <$> prodCons)
88− `HCons` (_openApiServers . extract <$> prodCons)
88+ `HCons` (_openApiServers . extract <$> prodCons)
89− `HCons` (tracedLinks <$> prodCons)
89+ `HCons` (tracedLinks <$> prodCons)
90− `HCons` (tracedCallbacks <$> prodCons)
90+ `HCons` (tracedCallbacks <$> prodCons)
91− `HCons` HNil
91+ `HCons` HNil)
92− )
93 (tracedPaths <$> prodCons)
92 (tracedPaths <$> prodCons)
94
93
95instance Steppable OpenApi ProcessedPathItems where
94instance Steppable OpenApi ProcessedPathItems where
src/Data/OpenApi/Compare/Validate/Operation.hs+24−26
@@ -4,17 +4,17 @@
4
4
5module Data.OpenApi.Compare.Validate.Operation
5module Data.OpenApi.Compare.Validate.Operation
6 ( -- * Operation
6 ( -- * Operation
7− MatchedOperation (..),
7+ MatchedOperation (..)
8− OperationMethod (..),
8+ , OperationMethod (..)
9− pathItemMethod,
9+ , pathItemMethod
10
10
11 -- * ProcessedPathItem
11 -- * ProcessedPathItem
12− ProcessedPathItem (..),
12+ , ProcessedPathItem (..)
13− ProcessedPathItems (..),
13+ , ProcessedPathItems (..)
14− processPathItems,
14+ , processPathItems
15− Step (..),
15+ , Step (..)
16− Behave (..),
16+ , Behave (..)
17− Issue (..),
17+ , Issue (..)
18 )
18 )
19where
19where
20
20
@@ -87,11 +87,10 @@ tracedCallbacks (Traced t oper) =
87 ]
87 ]
88
88
89-- FIXME: #28
89-- FIXME: #28
90−getServers ::
90+getServers
91− -- | Servers from env
91+ :: [Server] -- ^ Servers from env
92− [Server] ->
93− MatchedOperation ->
92+ -> MatchedOperation
94− [Server]
93+ -> [Server]
95getServers env oper =
94getServers env oper =
96 case _operationServers . operation $ oper of
95 case _operationServers . operation $ oper of
97 [] -> env
96 [] -> env
@@ -338,10 +337,9 @@ instance Issuable 'APILevel where
338 deriving stock (Eq, Ord, Show)
337 deriving stock (Eq, Ord, Show)
339 issueKind = \case
338 issueKind = \case
340 _ -> CertainIssue
339 _ -> CertainIssue
341− relatedIssues =
340+ relatedIssues = (==) `withClass` \case
342− (==) `withClass` \case
343− NoPathsMatched fp -> Just fp
341+ NoPathsMatched fp -> Just fp
344− AllPathsFailed fp -> Just fp
342+ AllPathsFailed fp -> Just fp
345 describeIssue Forward (NoPathsMatched p) = para $ "The path " <> (code . T.pack) p <> " has been removed."
343 describeIssue Forward (NoPathsMatched p) = para $ "The path " <> (code . T.pack) p <> " has been removed."
346 describeIssue Backward (NoPathsMatched p) = para $ "The path " <> (code . T.pack) p <> " has been added."
344 describeIssue Backward (NoPathsMatched p) = para $ "The path " <> (code . T.pack) p <> " has been added."
347 describeIssue Forward (AllPathsFailed p) = para $ "The path " <> (code . T.pack) p <> " has been removed."
345 describeIssue Forward (AllPathsFailed p) = para $ "The path " <> (code . T.pack) p <> " has been removed."
@@ -436,10 +434,10 @@ tracedFragments mpi =
436 | (i, x) <- L.zip [0 ..] $ pathFragments $ extract mpi
434 | (i, x) <- L.zip [0 ..] $ pathFragments $ extract mpi
437 ]
435 ]
438
436
439−tracedMethod ::
437+tracedMethod
440− OperationMethod ->
438+ :: OperationMethod
441− Traced MatchedPathItem ->
439+ -> Traced MatchedPathItem
442− Maybe (Traced' MatchedOperation Operation)
440+ -> Maybe (Traced' MatchedOperation Operation)
443tracedMethod s mpi = env (ask mpi >>> step (OperationMethodStep s)) <$> (pathItemMethod s . pathItem . extract $ mpi)
441tracedMethod s mpi = env (ask mpi >>> step (OperationMethodStep s)) <$> (pathItemMethod s . pathItem . extract $ mpi)
444
442
445instance Issuable 'PathLevel where
443instance Issuable 'PathLevel where
@@ -487,10 +485,10 @@ instance Subtree MatchedPathItem where
487 checkSemanticCompatibility env beh prodCons = do
485 checkSemanticCompatibility env beh prodCons = do
488 let paramDefs = getH @(ProdCons (Traced (Definitions Param))) env
486 let paramDefs = getH @(ProdCons (Traced (Definitions Param))) env
489 pathTracedParams = getPathParams <$> paramDefs <*> prodCons
487 pathTracedParams = getPathParams <$> paramDefs <*> prodCons
490− getPathParams ::
488+ getPathParams
491− Traced (Definitions Param) ->
489+ :: Traced (Definitions Param)
492− Traced MatchedPathItem ->
490+ -> Traced MatchedPathItem
493− [Traced Param]
491+ -> [Traced Param]
494 getPathParams defs mpi = do
492 getPathParams defs mpi = do
495 paramRef <- tracedMatchedPathItemParameters mpi
493 paramRef <- tracedMatchedPathItemParameters mpi
496 pure $ dereference defs paramRef
494 pure $ dereference defs paramRef
src/Data/OpenApi/Compare/Validate/Param.hs+7−9
@@ -2,8 +2,8 @@
2{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
2{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
3
3
4module Data.OpenApi.Compare.Validate.Param
4module Data.OpenApi.Compare.Validate.Param
5− ( Behave (..),
5+ ( Behave (..)
6− Issue (..),
6+ , Issue (..)
7 )
7 )
8where
8where
9
9
@@ -79,7 +79,7 @@ instance Issuable 'PathFragmentLevel where
79 describeIssue _ ParamPlaceIncompatible = para "Parameters in incompatible locations."
79 describeIssue _ ParamPlaceIncompatible = para "Parameters in incompatible locations."
80 describeIssue _ ParamStyleMismatch = para "Different parameter styles (encodings)."
80 describeIssue _ ParamStyleMismatch = para "Different parameter styles (encodings)."
81 describeIssue _ ParamSchemaMismatch = para "Expected a schema, but didn't find one."
81 describeIssue _ ParamSchemaMismatch = para "Expected a schema, but didn't find one."
82− describeIssue ori (PathFragmentsDontMatch (orientProdCons ori -> ProdCons e a)) =
82+ describeIssue ori (PathFragmentsDontMatch (orientProdCons ori -> ProdCons e a)) =
83 para $ "Parameter changed from " <> code e <> " to " <> code a <> "."
83 para $ "Parameter changed from " <> code e <> " to " <> code a <> "."
84
84
85instance Behavable 'PathFragmentLevel 'SchemaLevel where
85instance Behavable 'PathFragmentLevel 'SchemaLevel where
@@ -106,17 +106,15 @@ instance Subtree Param where
106 when (_paramName (extract p) /= _paramName (extract c)) $
106 when (_paramName (extract p) /= _paramName (extract c)) $
107 issueAt beh ParamNameMismatch
107 issueAt beh ParamNameMismatch
108 when
108 when
109− ( (fromMaybe False . _paramRequired . extract $ c)
109+ ((fromMaybe False . _paramRequired . extract $ c)
110− && not (fromMaybe False . _paramRequired . extract $ p)
110+ && not (fromMaybe False . _paramRequired . extract $ p))
111− )
112 $ issueAt beh ParamRequired
111 $ issueAt beh ParamRequired
113 case (_paramIn . extract $ p, _paramIn . extract $ c) of
112 case (_paramIn . extract $ p, _paramIn . extract $ c) of
114 (ParamQuery, ParamQuery) -> do
113 (ParamQuery, ParamQuery) -> do
115 -- Emptiness is only for query params
114 -- Emptiness is only for query params
116 when
115 when
117− ( (fromMaybe False . _paramAllowEmptyValue . extract $ p)
116+ ((fromMaybe False . _paramAllowEmptyValue . extract $ p)
118− && not (fromMaybe False . _paramAllowEmptyValue . extract $ c)
117+ && not (fromMaybe False . _paramAllowEmptyValue . extract $ c))
119− )
120 $ issueAt beh ParamEmptinessIncompatible
118 $ issueAt beh ParamEmptinessIncompatible
121 (a, b) | a == b -> pure ()
119 (a, b) | a == b -> pure ()
122 _ -> issueAt beh ParamPlaceIncompatible
120 _ -> issueAt beh ParamPlaceIncompatible
src/Data/OpenApi/Compare/Validate/PathFragment.hs+3−3
@@ -1,7 +1,7 @@
1module Data.OpenApi.Compare.Validate.PathFragment
1module Data.OpenApi.Compare.Validate.PathFragment
2− ( parsePath,
2+ ( parsePath
3− PathFragment (..),
3+ , PathFragment (..)
4− PathFragmentParam,
4+ , PathFragmentParam
5 )
5 )
6where
6where
7
7
src/Data/OpenApi/Compare/Validate/Products.hs+28−27
@@ -1,21 +1,21 @@
1−-- | Checks product-like entities. The key is some identificator for the product
1+{- | Checks product-like entities. The key is some identificator for the product
2−--element. Each element may be required or optional.
2+element. Each element may be required or optional.
3−--
3+
4−--One example of product is request parameters. There are optional and required
4+One example of product is request parameters. There are optional and required
5−--parameters. The client and server have possibly different set of
5+parameters. The client and server have possibly different set of
6−--parameters. What we must check is if server requires some request parameter,
6+parameters. What we must check is if server requires some request parameter,
7−--then this parameter must be presented by client and their schemas must match.
7+then this parameter must be presented by client and their schemas must match.
8−--
8+
9−--So when we checking products we are checking from the server's (consumer)
9+So when we checking products we are checking from the server's (consumer)
10−--perspective, ensuring that all parameters are provided by the client (producer)
10+perspective, ensuring that all parameters are provided by the client (producer)
11−--and their schemas match.
11+and their schemas match.
12−--
12+
13−--This module abstracts this logic for arbitrary elements
13+This module abstracts this logic for arbitrary elements -}
14+
14module Data.OpenApi.Compare.Validate.Products
15module Data.OpenApi.Compare.Validate.Products
15− ( checkProducts,
16+ ( checkProducts
16− ProductLike (..),
17+ , ProductLike(..)
17− )
18−where
18+ ) where
19
19
20import Data.Foldable
20import Data.Foldable
21import Data.Map.Strict (Map)
21import Data.Map.Strict (Map)
@@ -30,19 +30,20 @@ data ProductLike a = ProductLike
30 , required :: Bool
30 , required :: Bool
31 }
31 }
32
32
33−checkProducts ::
33+checkProducts
34− (Ord k, Issuable l) =>
34+ :: (Ord k, Issuable l)
35− Paths q r l ->
35+ => Paths q r l
36+ -> (k -> Issue l)
36− -- | No required element found
37+ -- ^ No required element found
37− (k -> Issue l) ->
38− (k -> ProdCons t -> CompatFormula' q AnIssue r ()) ->
38+ -> (k -> ProdCons t -> CompatFormula' q AnIssue r ())
39− ProdCons (Map k (ProductLike t)) ->
39+ -> ProdCons (Map k (ProductLike t))
40− CompatFormula' q AnIssue r ()
40+ -> CompatFormula' q AnIssue r ()
41checkProducts xs noElt check (ProdCons p c) = for_ (M.toList c) $ \(key, consElt) ->
41checkProducts xs noElt check (ProdCons p c) = for_ (M.toList c) $ \(key, consElt) ->
42 case M.lookup key p of
42 case M.lookup key p of
43 Nothing -> case required consElt of
43 Nothing -> case required consElt of
44− True -> issueAt xs $ noElt key
44+ True -> issueAt xs $ noElt key
45 False -> pure ()
45 False -> pure ()
46 Just prodElt -> do
46 Just prodElt -> do
47+ let
47− let elts = ProdCons prodElt consElt
48+ elts = ProdCons prodElt consElt
48 check key (productValue <$> elts)
49 check key (productValue <$> elts)
src/Data/OpenApi/Compare/Validate/RequestBody.hs+2−2
@@ -1,8 +1,8 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2
2
3module Data.OpenApi.Compare.Validate.RequestBody
3module Data.OpenApi.Compare.Validate.RequestBody
4− ( Issue (..),
4+ ( Issue (..)
5− Behave (..),
5+ , Behave (..)
6 )
6 )
7where
7where
8
8
src/Data/OpenApi/Compare/Validate/Responses.hs+1−1
@@ -2,7 +2,7 @@
2{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
2{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
3
3
4module Data.OpenApi.Compare.Validate.Responses
4module Data.OpenApi.Compare.Validate.Responses
5− ( Behave (..),
5+ ( Behave (..)
6 )
6 )
7where
7where
8
8
src/Data/OpenApi/Compare/Validate/Schema.hs+97−76
@@ -1,5 +1,4 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2−
3module Data.OpenApi.Compare.Validate.Schema
2module Data.OpenApi.Compare.Validate.Schema
4 (
3 (
5 )
4 )
@@ -11,9 +10,9 @@ import Data.Coerce
11import Data.Foldable (for_, toList)
10import Data.Foldable (for_, toList)
12import Data.Functor
11import Data.Functor
13import Data.HList
12import Data.HList
14−import Data.List (genericIndex, genericLength, group)
15import qualified Data.List.NonEmpty as NE
13import qualified Data.List.NonEmpty as NE
16import qualified Data.Map as M
14import qualified Data.Map as M
15+import Data.List (group, genericLength, genericIndex)
17import Data.Maybe
16import Data.Maybe
18import Data.OpenApi
17import Data.OpenApi
19import Data.OpenApi.Compare.Behavior
18import Data.OpenApi.Compare.Behavior
@@ -23,24 +22,24 @@ import Data.OpenApi.Compare.Subtree
23import Data.OpenApi.Compare.Validate.Schema.DNF
22import Data.OpenApi.Compare.Validate.Schema.DNF
24import Data.OpenApi.Compare.Validate.Schema.Issues
23import Data.OpenApi.Compare.Validate.Schema.Issues
25import Data.OpenApi.Compare.Validate.Schema.JsonFormula
24import Data.OpenApi.Compare.Validate.Schema.JsonFormula
26−import Data.OpenApi.Compare.Validate.Schema.Partition
27−import Data.OpenApi.Compare.Validate.Schema.Process
28import Data.OpenApi.Compare.Validate.Schema.Traced
25import Data.OpenApi.Compare.Validate.Schema.Traced
29import Data.OpenApi.Compare.Validate.Schema.TypedJson
26import Data.OpenApi.Compare.Validate.Schema.TypedJson
27+import Data.OpenApi.Compare.Validate.Schema.Partition
28+import Data.OpenApi.Compare.Validate.Schema.Process
30import Data.Ord
29import Data.Ord
31import Data.Ratio
30import Data.Ratio
32import Data.Semigroup
31import Data.Semigroup
33import qualified Data.Set as S
32import qualified Data.Set as S
34import Data.Text (Text)
33import Data.Text (Text)
35
34
36−checkFormulas ::
35+checkFormulas
37− (ReassembleHList xs (CheckEnv (Referenced Schema))) =>
36+ :: (ReassembleHList xs (CheckEnv (Referenced Schema)))
38− HList xs ->
37+ => HList xs
39− Behavior 'SchemaLevel ->
38+ -> Behavior 'SchemaLevel
40− ProdCons (Trace Schema) ->
39+ -> ProdCons (Trace Schema)
41− ProdCons (Traced (Definitions Schema)) ->
40+ -> ProdCons (Traced (Definitions Schema))
42− ProdCons (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel) ->
41+ -> ProdCons (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
43− SemanticCompatFormula ()
42+ -> SemanticCompatFormula ()
44checkFormulas env beh trs defs (ProdCons (fp, ep) (fc, ec)) =
43checkFormulas env beh trs defs (ProdCons (fp, ep) (fc, ec)) =
45 case P.toList ep ++ P.toList ec of
44 case P.toList ep ++ P.toList ec of
46 issues@(_ : _) -> for_ issues $ embedFormula beh . anItem
45 issues@(_ : _) -> for_ issues $ embedFormula beh . anItem
@@ -145,21 +144,21 @@ checkFormulas env beh trs defs (ProdCons (fp, ep) (fc, ec)) =
145 EnumDoesntSatisfy $ untypeValue e -- what does this look like when partitioned?
144 EnumDoesntSatisfy $ untypeValue e -- what does this look like when partitioned?
146 issueFromDisjunct mPart ps = NoMatchingCondition mPart $ SomeCondition <$> S.toList ps
145 issueFromDisjunct mPart ps = NoMatchingCondition mPart $ SomeCondition <$> S.toList ps
147
146
148−checkContradiction ::
147+checkContradiction
149− Behavior 'TypedSchemaLevel ->
148+ :: Behavior 'TypedSchemaLevel
150− Maybe Partition ->
149+ -> Maybe Partition
151− S.Set (Condition t) ->
150+ -> S.Set (Condition t)
152− SemanticCompatFormula ()
151+ -> SemanticCompatFormula ()
153checkContradiction beh mPart _ = issueAt beh $ maybe TypeBecomesEmpty PartitionBecomesEmpty mPart -- TODO #70
152checkContradiction beh mPart _ = issueAt beh $ maybe TypeBecomesEmpty PartitionBecomesEmpty mPart -- TODO #70
154
153
155−checkImplication ::
154+checkImplication
156− (ReassembleHList xs (CheckEnv (Referenced Schema))) =>
155+ :: (ReassembleHList xs (CheckEnv (Referenced Schema)))
157− HList xs ->
156+ => HList xs
158− Behavior 'TypedSchemaLevel ->
157+ -> Behavior 'TypedSchemaLevel
159− ProdCons (Trace Schema) -> -- the traces of the root schemas used in this comparison
158+ -> ProdCons (Trace Schema) -- the traces of the root schemas used in this comparison
160− S.Set (Condition t) ->
159+ -> S.Set (Condition t)
161− Condition t ->
160+ -> Condition t
162− SemanticCompatFormula ()
161+ -> SemanticCompatFormula ()
163checkImplication env beh trs prods cons = case findExactly prods of
162checkImplication env beh trs prods cons = case findExactly prods of
164 Just e
163 Just e
165 | all (satisfiesTyped e) prods ->
164 | all (satisfiesTyped e) prods ->
@@ -167,104 +166,124 @@ checkImplication env beh trs prods cons = case findExactly prods of
167 then pure ()
166 then pure ()
168 else issueAt beh (EnumDoesntSatisfy $ untypeValue e)
167 else issueAt beh (EnumDoesntSatisfy $ untypeValue e)
169 | otherwise -> pure () -- vacuously true
168 | otherwise -> pure () -- vacuously true
169+
170 Nothing -> case cons of
170 Nothing -> case cons of
171 -- the above code didn't catch it, so there's no Exactly condition on the lhs
171 -- the above code didn't catch it, so there's no Exactly condition on the lhs
172 Exactly e -> issueAt beh (NoMatchingEnum $ untypeValue e)
172 Exactly e -> issueAt beh (NoMatchingEnum $ untypeValue e)
173+
173 Maximum m -> foldCheck min m NoMatchingMaximum MatchingMaximumWeak $ \case
174 Maximum m -> foldCheck min m NoMatchingMaximum MatchingMaximumWeak $ \case
174 Maximum m' -> Just m'
175 Maximum m' -> Just m'
175 _ -> Nothing
176 _ -> Nothing
177+
176 Minimum m -> foldCheck max m (NoMatchingMinimum . coerce) (MatchingMinimumWeak . coerce) $ \case
178 Minimum m -> foldCheck max m (NoMatchingMinimum . coerce) (MatchingMinimumWeak . coerce) $ \case
177 Minimum m' -> Just m'
179 Minimum m' -> Just m'
178 _ -> Nothing
180 _ -> Nothing
181+
179 MultipleOf m -> foldCheck lcmScientific m NoMatchingMultipleOf MatchingMultipleOfWeak $ \case
182 MultipleOf m -> foldCheck lcmScientific m NoMatchingMultipleOf MatchingMultipleOfWeak $ \case
180 MultipleOf m' -> Just m'
183 MultipleOf m' -> Just m'
181 _ -> Nothing
184 _ -> Nothing
185+
182 NumberFormat f -> case flip any prods $ \case
186 NumberFormat f -> case flip any prods $ \case
183− NumberFormat f' -> f == f'
187+ NumberFormat f' -> f == f'
184− _ -> False of
188+ _ -> False
189+ of
185 True -> pure ()
190 True -> pure ()
186 False -> issueAt beh (NoMatchingFormat f)
191 False -> issueAt beh (NoMatchingFormat f)
192+
187 MaxLength m -> foldCheck min m NoMatchingMaxLength MatchingMaxLengthWeak $ \case
193 MaxLength m -> foldCheck min m NoMatchingMaxLength MatchingMaxLengthWeak $ \case
188 MaxLength m' -> Just m'
194 MaxLength m' -> Just m'
189 _ -> Nothing
195 _ -> Nothing
196+
190 MinLength m -> foldCheck max m NoMatchingMinLength MatchingMinLengthWeak $ \case
197 MinLength m -> foldCheck max m NoMatchingMinLength MatchingMinLengthWeak $ \case
191 MinLength m' -> Just m'
198 MinLength m' -> Just m'
192 _ -> Nothing
199 _ -> Nothing
200+
193 Pattern p -> case flip any prods $ \case
201 Pattern p -> case flip any prods $ \case
194− Pattern p' -> p == p'
202+ Pattern p' -> p == p'
195− _ -> False of
203+ _ -> False
204+ of
196 True -> pure ()
205 True -> pure ()
197 False -> issueAt beh (NoMatchingPattern p) -- TODO: regex comparison #32
206 False -> issueAt beh (NoMatchingPattern p) -- TODO: regex comparison #32
207+
198 StringFormat f -> case flip any prods $ \case
208 StringFormat f -> case flip any prods $ \case
199− StringFormat f' -> f == f'
209+ StringFormat f' -> f == f'
200− _ -> False of
210+ _ -> False
211+ of
201 True -> pure ()
212 True -> pure ()
202 False -> issueAt beh (NoMatchingFormat f)
213 False -> issueAt beh (NoMatchingFormat f)
214+
203 Items _ cons' -> case foldSome (<>) prods $ \case
215 Items _ cons' -> case foldSome (<>) prods $ \case
204− Items _ rs -> Just (Just (rs NE.:| []), mempty)
216+ Items _ rs -> Just (Just (rs NE.:| []), mempty)
205− TupleItems (map snd -> fs) -> Just (mempty, Just (fs NE.:| []))
217+ TupleItems (map snd -> fs) -> Just (mempty, Just (fs NE.:| []))
206− _ -> Nothing of
218+ _ -> Nothing
219+ of
207 Just (mItems, Just pfs)
220 Just (mItems, Just pfs)
208 | not $ allSame (length <$> pfs) -> pure () -- vacuously
221 | not $ allSame (length <$> pfs) -> pure () -- vacuously
209− | let plen = genericLength (NE.head pfs) ->
222+ | let plen = genericLength (NE.head pfs)
210− clarifyIssue (AnItem beh (anIssue TupleToArray)) $
223+ -> clarifyIssue (AnItem beh (anIssue TupleToArray)) $ for_ [0 .. plen - 1] $ \i -> do
211− for_ [0 .. plen - 1] $ \i -> do
212− let prod' = tracedConjunct $ case mItems of
224+ let prod' = tracedConjunct $ case mItems of
213− Just prods' -> ((`genericIndex` i) <$> pfs) <> prods'
225+ Just prods' -> ((`genericIndex` i) <$> pfs) <> prods'
214− Nothing -> (`genericIndex` i) <$> pfs
226+ Nothing -> (`genericIndex` i) <$> pfs
215− checkCompatibility (beh >>> step (InItem i)) env $ ProdCons prod' cons'
227+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons prod' cons'
216 Just (Just prods', Nothing) -> do
228 Just (Just prods', Nothing) -> do
217 let prod' = tracedConjunct prods'
229 let prod' = tracedConjunct prods'
218 checkCompatibility (beh >>> step InItems) env $ ProdCons prod' cons'
230 checkCompatibility (beh >>> step InItems) env $ ProdCons prod' cons'
219 _ -> clarifyIssue (AnItem beh (anIssue NoMatchingItems)) $ do
231 _ -> clarifyIssue (AnItem beh (anIssue NoMatchingItems)) $ do
220 checkCompatibility (beh >>> step InItems) env $ ProdCons prodTopSchema cons'
232 checkCompatibility (beh >>> step InItems) env $ ProdCons prodTopSchema cons'
233+
221 TupleItems (map snd -> fs) -> case foldSome (<>) prods $ \case
234 TupleItems (map snd -> fs) -> case foldSome (<>) prods $ \case
222− TupleItems (map snd -> fs') -> Just (Just $ fs' NE.:| [], Just . Max $ genericLength fs', Just . Min $ genericLength fs', mempty)
235+ TupleItems (map snd -> fs') -> Just (Just $ fs' NE.:| [], Just . Max $ genericLength fs', Just . Min $ genericLength fs', mempty)
223− MinItems m' -> Just (mempty, Just . Max $ m', mempty, mempty)
236+ MinItems m' -> Just (mempty, Just . Max $ m', mempty, mempty)
224− MaxItems m' -> Just (mempty, mempty, Just . Min $ m', mempty)
237+ MaxItems m' -> Just (mempty, mempty, Just . Min $ m', mempty)
225− Items _ rs -> Just (mempty, mempty, mempty, Just (rs NE.:| []))
238+ Items _ rs -> Just (mempty, mempty, mempty, Just (rs NE.:| []))
226− _ -> Nothing of
239+ _ -> Nothing
240+ of
227− -- if the length constraints in the producer are contradictory:
241+ -- if the length constraints in the producer are contradictory:
228− Just (_, Just (Max lowest), Just (Min highest), _) | lowest > highest -> pure ()
242+ Just (_, Just (Max lowest), Just (Min highest), _) | lowest > highest -> pure ()
229− -- We have an explicit tuple items clause...
243+ -- We have an explicit tuple items clause...
230− Just (Just pfs, Just (Max plen), _, _)
244+ Just (Just pfs, Just (Max plen), _, _)
231− | plen /= genericLength fs -> -- ...of wrong length
245+ | plen /= genericLength fs -- ...of wrong length
232− issueAt beh (TupleItemsLengthChanged ProdCons {producer = plen, consumer = genericLength fs})
246+ -> issueAt beh (TupleItemsLengthChanged ProdCons {producer = plen, consumer = genericLength fs})
233− | otherwise ->
247+ | otherwise
234− for_ [0 .. plen - 1] $ \i -> do
248+ -> for_ [0 .. plen - 1] $ \i -> do
235 checkCompatibility (beh >>> step (InItem i)) env $ ProdCons (tracedConjunct $ (`genericIndex` i) <$> pfs) (fs `genericIndex` i)
249 checkCompatibility (beh >>> step (InItem i)) env $ ProdCons (tracedConjunct $ (`genericIndex` i) <$> pfs) (fs `genericIndex` i)
236− -- We have a fixed length array in the producer...
250+ -- We have a fixed length array in the producer...
237− Just (Nothing, Just (Max plen), Just (Min plen'), mProd)
251+ Just (Nothing, Just (Max plen), Just (Min plen'), mProd)
238− | plen == plen' ->
252+ | plen == plen'
239− clarifyIssue (AnItem beh (anIssue ArrayToTuple)) $ case mProd of
253+ -> clarifyIssue (AnItem beh (anIssue ArrayToTuple)) $ case mProd of
240− _
241− | plen /= genericLength fs -> -- ...of wrong length
254+ _ | plen /= genericLength fs -> -- ...of wrong length
242− issueAt beh (TupleItemsLengthChanged ProdCons {producer = plen, consumer = genericLength fs})
255+ issueAt beh (TupleItemsLengthChanged ProdCons {producer = plen, consumer = genericLength fs})
243 Just rs -> for_ [0 .. plen - 1] $ \i -> do
256 Just rs -> for_ [0 .. plen - 1] $ \i -> do
244 checkCompatibility (beh >>> step (InItem i)) env $ ProdCons (tracedConjunct rs) (fs `genericIndex` i)
257 checkCompatibility (beh >>> step (InItem i)) env $ ProdCons (tracedConjunct rs) (fs `genericIndex` i)
245 -- ...and no "items" schema
258 -- ...and no "items" schema
246 Nothing -> clarifyIssue (AnItem beh (anIssue NoMatchingTupleItems)) $ do
259 Nothing -> clarifyIssue (AnItem beh (anIssue NoMatchingTupleItems)) $ do
247 for_ [0 .. plen - 1] $ \i -> do
260 for_ [0 .. plen - 1] $ \i -> do
248 checkCompatibility (beh >>> step (InItem i)) env $ ProdCons prodTopSchema (fs `genericIndex` i)
261 checkCompatibility (beh >>> step (InItem i)) env $ ProdCons prodTopSchema (fs `genericIndex` i)
249− _ -> issueAt beh NoMatchingTupleItems
262+ _ -> issueAt beh NoMatchingTupleItems
263+
250 MaxItems m -> foldCheck min m NoMatchingMaxItems MatchingMaxItemsWeak $ \case
264 MaxItems m -> foldCheck min m NoMatchingMaxItems MatchingMaxItemsWeak $ \case
251 MaxItems m' -> Just m'
265 MaxItems m' -> Just m'
252 TupleItems fs -> Just $ toInteger $ length fs
266 TupleItems fs -> Just $ toInteger $ length fs
253 _ -> Nothing
267 _ -> Nothing
268+
254 MinItems m -> foldCheck max m NoMatchingMinItems MatchingMinItemsWeak $ \case
269 MinItems m -> foldCheck max m NoMatchingMinItems MatchingMinItemsWeak $ \case
255 MinItems m' -> Just m'
270 MinItems m' -> Just m'
256 TupleItems fs -> Just $ toInteger $ length fs
271 TupleItems fs -> Just $ toInteger $ length fs
257 _ -> Nothing
272 _ -> Nothing
273+
258 UniqueItems -> case flip any prods $ \case
274 UniqueItems -> case flip any prods $ \case
259− UniqueItems -> True
275+ UniqueItems -> True
260− MaxItems 1 -> True
276+ MaxItems 1 -> True
261− TupleItems fs | length fs == 1 -> True
277+ TupleItems fs | length fs == 1 -> True
262− _ -> False of
278+ _ -> False
279+ of
263 True -> pure ()
280 True -> pure ()
264 False -> issueAt beh NoMatchingUniqueItems
281 False -> issueAt beh NoMatchingUniqueItems
282+
265 Properties props _ madd -> case foldSome (<>) prods $ \case
283 Properties props _ madd -> case foldSome (<>) prods $ \case
266− Properties props' _ madd' -> Just $ (props', madd') NE.:| []
284+ Properties props' _ madd' -> Just $ (props', madd') NE.:| []
267− _ -> Nothing of
285+ _ -> Nothing
286+ of
268 Just pm ->
287 Just pm ->
269 anyOfAt beh NoMatchingProperties $ -- TODO: could first "concat" the lists
288 anyOfAt beh NoMatchingProperties $ -- TODO: could first "concat" the lists
270 NE.toList pm <&> \(props', madd') -> do
289 NE.toList pm <&> \(props', madd') -> do
@@ -295,9 +314,11 @@ checkImplication env beh trs prods cons = case findExactly prods of
295 (Just add', Just add) -> checkCompatibility (beh >>> step InAdditionalProperty) env (ProdCons add' add)
314 (Just add', Just add) -> checkCompatibility (beh >>> step InAdditionalProperty) env (ProdCons add' add)
296 pure ()
315 pure ()
297 Nothing -> issueAt beh NoMatchingProperties
316 Nothing -> issueAt beh NoMatchingProperties
317+
298 MaxProperties m -> foldCheck min m NoMatchingMaxProperties MatchingMaxPropertiesWeak $ \case
318 MaxProperties m -> foldCheck min m NoMatchingMaxProperties MatchingMaxPropertiesWeak $ \case
299 MaxProperties m' -> Just m'
319 MaxProperties m' -> Just m'
300 _ -> Nothing
320 _ -> Nothing
321+
301 MinProperties m -> foldCheck max m NoMatchingMinProperties MatchingMinPropertiesWeak $ \case
322 MinProperties m -> foldCheck max m NoMatchingMinProperties MatchingMinPropertiesWeak $ \case
302 MinProperties m' -> Just m'
323 MinProperties m' -> Just m'
303 _ -> Nothing
324 _ -> Nothing
@@ -305,14 +326,14 @@ checkImplication env beh trs prods cons = case findExactly prods of
305 lcmScientific (toRational -> a) (toRational -> b) =
326 lcmScientific (toRational -> a) (toRational -> b) =
306 fromRational $ lcm (numerator a) (numerator b) % gcd (denominator a) (denominator b)
327 fromRational $ lcm (numerator a) (numerator b) % gcd (denominator a) (denominator b)
307
328
308− foldCheck ::
329+ foldCheck
309− Eq a =>
330+ :: Eq a
310− (a -> a -> a) ->
331+ => (a -> a -> a)
311− a ->
332+ -> a
312− (a -> Issue 'TypedSchemaLevel) ->
333+ -> (a -> Issue 'TypedSchemaLevel)
313− (ProdCons a -> Issue 'TypedSchemaLevel) ->
334+ -> (ProdCons a -> Issue 'TypedSchemaLevel)
314− (forall t. Condition t -> Maybe a) ->
335+ -> (forall t. Condition t -> Maybe a)
315− SemanticCompatFormula ()
336+ -> SemanticCompatFormula ()
316 foldCheck f m missing weak extr = case foldSome f prods extr of
337 foldCheck f m missing weak extr = case foldSome f prods extr of
317 Just m'
338 Just m'
318 | f m' m == m' -> pure ()
339 | f m' m == m' -> pure ()
src/Data/OpenApi/Compare/Validate/Schema/DNF.hs+8−8
@@ -1,12 +1,12 @@
1module Data.OpenApi.Compare.Validate.Schema.DNF
1module Data.OpenApi.Compare.Validate.Schema.DNF
2− ( DNF (..),
2+ ( DNF (..)
3− Disjunct (..),
3+ , Disjunct (..)
4− pattern SingleDisjunct,
4+ , pattern SingleDisjunct
5− pattern TopDNF,
5+ , pattern TopDNF
6− pattern BottomDNF,
6+ , pattern BottomDNF
7− pattern LiteralDNF,
7+ , pattern LiteralDNF
8− foldDNF,
8+ , foldDNF
9− forDNF,
9+ , forDNF
10 )
10 )
11where
11where
12
12
src/Data/OpenApi/Compare/Validate/Schema/Issues.hs+51−53
@@ -1,8 +1,8 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2
2
3module Data.OpenApi.Compare.Validate.Schema.Issues
3module Data.OpenApi.Compare.Validate.Schema.Issues
4− ( Issue (..),
4+ ( Issue (..)
5− Behave (..),
5+ , Behave (..)
6 )
6 )
7where
7where
8
8
@@ -100,54 +100,53 @@ instance Issuable 'TypedSchemaLevel where
100 TypeBecomesEmpty -> ProbablyIssue -- TODO: #70
100 TypeBecomesEmpty -> ProbablyIssue -- TODO: #70
101 PartitionBecomesEmpty _ -> ProbablyIssue -- ditto
101 PartitionBecomesEmpty _ -> ProbablyIssue -- ditto
102 _ -> CertainIssue
102 _ -> CertainIssue
103− relatedIssues =
103+ relatedIssues = (==) `withClass` \case
104− (==) `withClass` \case
105 EnumDoesntSatisfy v -> Just v
104 EnumDoesntSatisfy v -> Just v
106 NoMatchingEnum v -> Just v
105 NoMatchingEnum v -> Just v
107 _ -> Nothing
106 _ -> Nothing
108− `withClass` \case
107+ `withClass` \case
109− NoMatchingMaximum _ -> Just ()
108+ NoMatchingMaximum _ -> Just ()
110− MatchingMaximumWeak _ -> Just ()
109+ MatchingMaximumWeak _ -> Just ()
111− _ -> Nothing
110+ _ -> Nothing
112− `withClass` \case
111+ `withClass` \case
113− NoMatchingMinimum _ -> Just ()
112+ NoMatchingMinimum _ -> Just ()
114− MatchingMinimumWeak _ -> Just ()
113+ MatchingMinimumWeak _ -> Just ()
115− _ -> Nothing
114+ _ -> Nothing
116− `withClass` \case
115+ `withClass` \case
117− NoMatchingMultipleOf _ -> Just ()
116+ NoMatchingMultipleOf _ -> Just ()
118− MatchingMultipleOfWeak _ -> Just ()
117+ MatchingMultipleOfWeak _ -> Just ()
119− _ -> Nothing
118+ _ -> Nothing
120− `withClass` \case
119+ `withClass` \case
121− NoMatchingMaxLength _ -> Just ()
120+ NoMatchingMaxLength _ -> Just ()
122− MatchingMaxLengthWeak _ -> Just ()
121+ MatchingMaxLengthWeak _ -> Just ()
123− _ -> Nothing
122+ _ -> Nothing
124− `withClass` \case
123+ `withClass` \case
125− NoMatchingMinLength _ -> Just ()
124+ NoMatchingMinLength _ -> Just ()
126− MatchingMinLengthWeak _ -> Just ()
125+ MatchingMinLengthWeak _ -> Just ()
127− _ -> Nothing
126+ _ -> Nothing
128− `withClass` \case
127+ `withClass` \case
129− NoMatchingItems -> Just ()
128+ NoMatchingItems -> Just ()
130− ArrayToTuple -> Just ()
129+ ArrayToTuple -> Just ()
131− TupleToArray -> Just ()
130+ TupleToArray -> Just ()
132− NoMatchingTupleItems -> Just ()
131+ NoMatchingTupleItems -> Just ()
133− TupleItemsLengthChanged _ -> Just ()
132+ TupleItemsLengthChanged _ -> Just ()
134− _ -> Nothing
133+ _ -> Nothing
135− `withClass` \case
134+ `withClass` \case
136− NoMatchingMaxItems _ -> Just ()
135+ NoMatchingMaxItems _ -> Just ()
137− MatchingMaxItemsWeak _ -> Just ()
136+ MatchingMaxItemsWeak _ -> Just ()
138− _ -> Nothing
137+ _ -> Nothing
139− `withClass` \case
138+ `withClass` \case
140− NoMatchingMinItems _ -> Just ()
139+ NoMatchingMinItems _ -> Just ()
141− MatchingMinItemsWeak _ -> Just ()
140+ MatchingMinItemsWeak _ -> Just ()
142− _ -> Nothing
141+ _ -> Nothing
143− `withClass` \case
142+ `withClass` \case
144− NoMatchingMaxProperties _ -> Just ()
143+ NoMatchingMaxProperties _ -> Just ()
145− MatchingMaxPropertiesWeak _ -> Just ()
144+ MatchingMaxPropertiesWeak _ -> Just ()
146− _ -> Nothing
145+ _ -> Nothing
147− `withClass` \case
146+ `withClass` \case
148− NoMatchingMinProperties _ -> Just ()
147+ NoMatchingMinProperties _ -> Just ()
149− MatchingMinPropertiesWeak _ -> Just ()
148+ MatchingMinPropertiesWeak _ -> Just ()
150− _ -> Nothing
149+ _ -> Nothing
151 describeIssue Forward (EnumDoesntSatisfy v) = para "The following enum value was removed:" <> showJSONValue v
150 describeIssue Forward (EnumDoesntSatisfy v) = para "The following enum value was removed:" <> showJSONValue v
152 describeIssue Backward (EnumDoesntSatisfy v) = para "The following enum value was added:" <> showJSONValue v
151 describeIssue Backward (EnumDoesntSatisfy v) = para "The following enum value was added:" <> showJSONValue v
153 describeIssue Forward (NoMatchingEnum v) = para "The following enum value has been added:" <> showJSONValue v
152 describeIssue Forward (NoMatchingEnum v) = para "The following enum value has been added:" <> showJSONValue v
@@ -255,15 +254,14 @@ instance Issuable 'SchemaLevel where
255 PropertyToAdditional -> Comment
254 PropertyToAdditional -> Comment
256 TypesRestricted _ -> ProbablyIssue -- TODO: #70
255 TypesRestricted _ -> ProbablyIssue -- TODO: #70
257 _ -> CertainIssue
256 _ -> CertainIssue
258− relatedIssues =
257+ relatedIssues = (==) `withClass` \case
259− (==) `withClass` \case
260 AdditionalToProperty -> Just ()
258 AdditionalToProperty -> Just ()
261 PropertyToAdditional -> Just ()
259 PropertyToAdditional -> Just ()
262 _ -> Nothing
260 _ -> Nothing
263− `withClass` \case
261+ `withClass` \case
264− PropertyNowRequired -> Just ()
262+ PropertyNowRequired -> Just ()
265− UnexpectedProperty -> Just ()
263+ UnexpectedProperty -> Just ()
266− _ -> Nothing
264+ _ -> Nothing
267 describeIssue _ (NotSupported i) =
265 describeIssue _ (NotSupported i) =
268 para (emph "Encountered a feature that CompaREST does not support: " <> text i <> ".")
266 para (emph "Encountered a feature that CompaREST does not support: " <> text i <> ".")
269 describeIssue _ OneOfNotDisjoint =
267 describeIssue _ OneOfNotDisjoint =
src/Data/OpenApi/Compare/Validate/Schema/JsonFormula.hs+43−50
@@ -1,18 +1,18 @@
1module Data.OpenApi.Compare.Validate.Schema.JsonFormula
1module Data.OpenApi.Compare.Validate.Schema.JsonFormula
2− ( Bound (..),
2+ ( Bound (..)
3− showBound,
3+ , showBound
4− Property (..),
4+ , Property (..)
5− Condition (..),
5+ , Condition (..)
6− showCondition,
6+ , showCondition
7− satisfiesTyped,
7+ , satisfiesTyped
8− checkStringFormat,
8+ , checkStringFormat
9− checkNumberFormat,
9+ , checkNumberFormat
10− SomeCondition (..),
10+ , SomeCondition (..)
11− JsonFormula (..),
11+ , JsonFormula (..)
12− satisfiesFormula,
12+ , satisfiesFormula
13− satisfies,
13+ , satisfies
14− showJSONValue,
14+ , showJSONValue
15− showJSONValueInline,
15+ , showJSONValueInline
16 )
16 )
17where
17where
18
18
@@ -20,8 +20,8 @@ import Algebra.Lattice
20import qualified Data.Aeson as A
20import qualified Data.Aeson as A
21import qualified Data.ByteString.Lazy as BSL
21import qualified Data.ByteString.Lazy as BSL
22import qualified Data.Foldable as F
22import qualified Data.Foldable as F
23−import Data.Functor
24import qualified Data.HashMap.Strict as HM
23import qualified Data.HashMap.Strict as HM
24+import Data.Functor
25import Data.Int
25import Data.Int
26import Data.Kind
26import Data.Kind
27import qualified Data.Map as M
27import qualified Data.Map as M
@@ -67,33 +67,30 @@ data Property = Property
67data Condition :: JsonType -> Type where
67data Condition :: JsonType -> Type where
68 Exactly :: TypedValue t -> Condition t
68 Exactly :: TypedValue t -> Condition t
69 Maximum :: !(Bound Scientific) -> Condition 'Number
69 Maximum :: !(Bound Scientific) -> Condition 'Number
70− Minimum ::
70+ Minimum
71− !(Down (Bound (Down Scientific))) ->
71+ :: !(Down (Bound (Down Scientific)))
72− -- | this has the right Ord
72+ -> Condition 'Number -- ^ this has the right Ord
73− Condition 'Number
74 MultipleOf :: !Scientific -> Condition 'Number
73 MultipleOf :: !Scientific -> Condition 'Number
75 NumberFormat :: !Format -> Condition 'Number
74 NumberFormat :: !Format -> Condition 'Number
76 MaxLength :: !Integer -> Condition 'String
75 MaxLength :: !Integer -> Condition 'String
77 MinLength :: !Integer -> Condition 'String
76 MinLength :: !Integer -> Condition 'String
78 Pattern :: !Pattern -> Condition 'String
77 Pattern :: !Pattern -> Condition 'String
79 StringFormat :: !Format -> Condition 'String
78 StringFormat :: !Format -> Condition 'String
80− Items ::
79+ Items
81− !(ForeachType JsonFormula) ->
80+ :: !(ForeachType JsonFormula)
82− !(Traced (Referenced Schema)) ->
81+ -> !(Traced (Referenced Schema))
83− Condition 'Array
82+ -> Condition 'Array
84− TupleItems ::
83+ TupleItems
85− ![(ForeachType JsonFormula, Traced (Referenced Schema))] ->
84+ :: ![(ForeachType JsonFormula, Traced (Referenced Schema))]
86− Condition 'Array
85+ -> Condition 'Array
87 MaxItems :: !Integer -> Condition 'Array
86 MaxItems :: !Integer -> Condition 'Array
88 MinItems :: !Integer -> Condition 'Array
87 MinItems :: !Integer -> Condition 'Array
89 UniqueItems :: Condition 'Array
88 UniqueItems :: Condition 'Array
90− Properties ::
89+ Properties
91− !(M.Map Text Property) ->
90+ :: !(M.Map Text Property)
92− -- | formula for additional properties
93− !(ForeachType JsonFormula) ->
91+ -> !(ForeachType JsonFormula) -- ^ formula for additional properties
94− -- | schema for additional properties, Nothing means bottom
92+ -> !(Maybe (Traced (Referenced Schema))) -- ^ schema for additional properties, Nothing means bottom
95− !(Maybe (Traced (Referenced Schema))) ->
96− Condition 'Object
93+ -> Condition 'Object
97 MaxProperties :: !Integer -> Condition 'Object
94 MaxProperties :: !Integer -> Condition 'Object
98 MinProperties :: !Integer -> Condition 'Object
95 MinProperties :: !Integer -> Condition 'Object
99
96
@@ -121,15 +118,13 @@ showCondition = \case
121 UniqueItems -> para "The elements in the array should be unique."
118 UniqueItems -> para "The elements in the array should be unique."
122 (Properties props additional _) ->
119 (Properties props additional _) ->
123 bulletList $
120 bulletList $
124− ( M.toList props
121+ (M.toList props
125− <&> ( \(k, p) ->
122+ <&> (\(k, p) ->
126− para (code k)
123+ para (code k)
127− <> para (strong $ if propRequired p then "Required" else "Optional")
124+ <> para (strong $ if propRequired p then "Required" else "Optional")
128− <> showForEachJsonFormula (propFormula p)
125+ <> showForEachJsonFormula (propFormula p)))
129− )
130− )
131 <> [ para (emph "Additional properties")
126 <> [ para (emph "Additional properties")
132− <> showForEachJsonFormula additional
127+ <> showForEachJsonFormula additional
133 ]
128 ]
134 (MaxProperties n) -> para $ "The maximum number of fields should be " <> show' n <> "."
129 (MaxProperties n) -> para $ "The maximum number of fields should be " <> show' n <> "."
135 (MinProperties n) -> para $ "The minimum number of fields should be " <> show' n <> "."
130 (MinProperties n) -> para $ "The minimum number of fields should be " <> show' n <> "."
@@ -138,17 +133,15 @@ showCondition = \case
138 showForEachJsonFormula i =
133 showForEachJsonFormula i =
139 bulletList $
134 bulletList $
140 foldType
135 foldType
141− ( \t f -> case getJsonFormula $ f i of
136+ (\t f -> case getJsonFormula $ f i of
142− BottomDNF -> mempty
137+ BottomDNF -> mempty
143− (DNF conds) ->
138+ (DNF conds) ->
144 [ para (describeJSONType t)
139 [ para (describeJSONType t)
145 <> bulletList
140 <> bulletList
146− ( S.toList conds <&> \case
141+ (S.toList conds <&> \case
147− Disjunct (S.toList -> []) -> para "Empty"
142+ Disjunct (S.toList -> []) -> para "Empty"
148− Disjunct (S.toList -> cond) -> bulletList (showCondition <$> cond)
143+ Disjunct (S.toList -> cond) -> bulletList (showCondition <$> cond))
149− )
150− ]
144+ ])
151− )
152
145
153showJSONValue :: A.Value -> Blocks
146showJSONValue :: A.Value -> Blocks
154showJSONValue v = codeBlockWith ("", ["json"], mempty) (T.decodeUtf8 . BSL.toStrict . A.encode $ v)
147showJSONValue v = codeBlockWith ("", ["json"], mempty) (T.decodeUtf8 . BSL.toStrict . A.encode $ v)
src/Data/OpenApi/Compare/Validate/Schema/Partition.hs+29−30
@@ -1,15 +1,15 @@
1module Data.OpenApi.Compare.Validate.Schema.Partition
1module Data.OpenApi.Compare.Validate.Schema.Partition
2− ( partitionSchema,
2+ ( partitionSchema
3− partitionRefSchema,
3+ , partitionRefSchema
4− selectPartition,
4+ , selectPartition
5− runPartitionM,
5+ , runPartitionM
6− tryPartition,
6+ , tryPartition
7− showPartition,
7+ , showPartition
8− intersectSchema,
8+ , intersectSchema
9− intersectRefSchema,
9+ , intersectRefSchema
10− IntersectionResult (..),
10+ , IntersectionResult (..)
11− runIntersectionM,
11+ , runIntersectionM
12− Partition,
12+ , Partition
13 )
13 )
14where
14where
15
15
@@ -143,11 +143,10 @@ partitionCondition = \case
143 Just _ -> top
143 Just _ -> top
144 Nothing ->
144 Nothing ->
145 singletonPart $
145 singletonPart $
146− DByProperties $
146+ DByProperties $ LiteralDNF
147− LiteralDNF
148− ( M.keysSet $ M.filter (not . propRequired) props
147+ ( M.keysSet $ M.filter (not . propRequired) props
149− , M.keysSet $ M.filter propRequired props
148+ , M.keysSet $ M.filter propRequired props
150− )
149+ )
151 inProps <- forM (M.toList $ M.filter propRequired props) $ \(k, prop) -> do
150 inProps <- forM (M.toList $ M.filter propRequired props) $ \(k, prop) -> do
152 f <- partitionRefSchema $ propRefSchema prop
151 f <- partitionRefSchema $ propRefSchema prop
153 pure $ fmap (\(Partitions m) -> Partitions $ M.mapKeysMonotonic (PInProperty k) m) f
152 pure $ fmap (\(Partitions m) -> Partitions $ M.mapKeysMonotonic (PInProperty k) m) f
@@ -157,10 +156,10 @@ partitionCondition = \case
157runPartitionM :: Traced (Definitions Schema) -> PartitionM a -> a
156runPartitionM :: Traced (Definitions Schema) -> PartitionM a -> a
158runPartitionM defs = runIdentity . runMemo () . (`runReaderT` defs)
157runPartitionM defs = runIdentity . runMemo () . (`runReaderT` defs)
159
158
160−partitionJsonFormulas ::
159+partitionJsonFormulas
161− ProdCons (Traced (Definitions Schema)) ->
160+ :: ProdCons (Traced (Definitions Schema))
162− ProdCons (JsonFormula t) ->
161+ -> ProdCons (JsonFormula t)
163− Lifted Partitions
162+ -> Lifted Partitions
164partitionJsonFormulas defs pc = producer pcPart \/ consumer pcPart
163partitionJsonFormulas defs pc = producer pcPart \/ consumer pcPart
165 where
164 where
166 pcPart = partitionFormula <$> defs <*> pc
165 pcPart = partitionFormula <$> defs <*> pc
@@ -212,11 +211,11 @@ runIntersectionM defs act = case runWriterT $ runReaderT act defs of
212 Just (x, Any False) -> Same x
211 Just (x, Any False) -> Same x
213 Just (x, Any True) -> New x
212 Just (x, Any True) -> New x
214
213
215−intersectSchema ::
214+intersectSchema
216− PartitionLocation ->
215+ :: PartitionLocation
217− PartitionChoice ->
216+ -> PartitionChoice
218− Traced Schema ->
217+ -> Traced Schema
219− IntersectionM Schema
218+ -> IntersectionM Schema
220intersectSchema loc part sch = do
219intersectSchema loc part sch = do
221 allOf' <- forM (tracedAllOf sch) $ \rss ->
220 allOf' <- forM (tracedAllOf sch) $ \rss ->
222 -- Assuming i ranges over a nonempty set (checked in processSchema)
221 -- Assuming i ranges over a nonempty set (checked in processSchema)
@@ -259,11 +258,11 @@ intersectSchema loc part sch = do
259 pure $ sch' {_schemaEnum = Just enum'}
258 pure $ sch' {_schemaEnum = Just enum'}
260 CByProperties {} -> error "CByProperties not implemented"
259 CByProperties {} -> error "CByProperties not implemented"
261
260
262−intersectRefSchema ::
261+intersectRefSchema
263− PartitionLocation ->
262+ :: PartitionLocation
264− PartitionChoice ->
263+ -> PartitionChoice
265− Traced (Referenced Schema) ->
264+ -> Traced (Referenced Schema)
266− IntersectionM (Referenced Schema)
265+ -> IntersectionM (Referenced Schema)
267intersectRefSchema loc part rs = do
266intersectRefSchema loc part rs = do
268 defs <- R.ask
267 defs <- R.ask
269 Inline <$> intersectSchema loc part (dereference defs rs)
268 Inline <$> intersectSchema loc part (dereference defs rs)
src/Data/OpenApi/Compare/Validate/Schema/Process.hs+34−35
@@ -1,11 +1,11 @@
1module Data.OpenApi.Compare.Validate.Schema.Process
1module Data.OpenApi.Compare.Validate.Schema.Process
2− ( schemaToFormula,
2+ ( schemaToFormula
3 )
3 )
4where
4where
5
5
6import Algebra.Lattice
6import Algebra.Lattice
7−import Control.Monad.Reader hiding (ask)
8import qualified Control.Monad.Reader as R
7import qualified Control.Monad.Reader as R
8+import Control.Monad.Reader hiding (ask)
9import Control.Monad.State
9import Control.Monad.State
10import Control.Monad.Writer
10import Control.Monad.Writer
11import qualified Data.Aeson as A
11import qualified Data.Aeson as A
@@ -71,10 +71,10 @@ warnKnot =
71 , tieKnot = \_ -> pure
71 , tieKnot = \_ -> pure
72 }
72 }
73
73
74−processRefSchema ::
74+processRefSchema
75− MonadProcess m =>
75+ :: MonadProcess m
76− Traced (Referenced Schema) ->
76+ => Traced (Referenced Schema)
77− m (ForeachType JsonFormula)
77+ -> m (ForeachType JsonFormula)
78processRefSchema x = do
78processRefSchema x = do
79 defs <- R.ask
79 defs <- R.ask
80 memoWithKnot warnKnot (processSchema $ dereference defs x) (ask x)
80 memoWithKnot warnKnot (processSchema $ dereference defs x) (ask x)
@@ -82,10 +82,10 @@ processRefSchema x = do
82-- | Turn a schema into a tuple of 'JsonFormula's that describes the condition
82-- | Turn a schema into a tuple of 'JsonFormula's that describes the condition
83-- for every possible type of a JSON value. The conditions are independent, and
83-- for every possible type of a JSON value. The conditions are independent, and
84-- are thus checked independently.
84-- are thus checked independently.
85−processSchema ::
85+processSchema
86− MonadProcess m =>
86+ :: MonadProcess m
87− Traced Schema ->
87+ => Traced Schema
88− m (ForeachType JsonFormula)
88+ -> m (ForeachType JsonFormula)
89processSchema sch@(extract -> Schema {..}) = do
89processSchema sch@(extract -> Schema {..}) = do
90 let singletonFormula :: Condition t -> JsonFormula t
90 let singletonFormula :: Condition t -> JsonFormula t
91 singletonFormula = JsonFormula . LiteralDNF
91 singletonFormula = JsonFormula . LiteralDNF
@@ -331,27 +331,26 @@ processSchema sch@(extract -> Schema {..}) = do
331 pure $
331 pure $
332 nullableClause
332 nullableClause
333 \/ meets
333 \/ meets
334− ( allClauses
334+ (allClauses
335− <> [ anyClause
335+ <> [ anyClause
336− , oneClause
336+ , oneClause
337− , typeClause
337+ , typeClause
338− , enumClause
338+ , enumClause
339− , maximumClause
339+ , maximumClause
340− , minimumClause
340+ , minimumClause
341− , multipleOfClause
341+ , multipleOfClause
342− , formatClause
342+ , formatClause
343− , maxLengthClause
343+ , maxLengthClause
344− , minLengthClause
344+ , minLengthClause
345− , patternClause
345+ , patternClause
346− , itemsClause
346+ , itemsClause
347− , maxItemsClause
347+ , maxItemsClause
348− , minItemsClause
348+ , minItemsClause
349− , uniqueItemsClause
349+ , uniqueItemsClause
350− , propertiesClause
350+ , propertiesClause
351− , maxPropertiesClause
351+ , maxPropertiesClause
352− , minPropertiesClause
352+ , minPropertiesClause
353− ]
353+ ])
354− )
355
354
356{- TODO: ReadOnly/WriteOnly #68 -}
355{- TODO: ReadOnly/WriteOnly #68 -}
357
356
@@ -370,8 +369,8 @@ checkOneOfDisjoint schs = do
370runProcessM :: Traced (Definitions Schema) -> ProcessM a -> (a, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
369runProcessM :: Traced (Definitions Schema) -> ProcessM a -> (a, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
371runProcessM defs = runWriter . (`runReaderT` defs) . runMemo ()
370runProcessM defs = runWriter . (`runReaderT` defs) . runMemo ()
372
371
373−schemaToFormula ::
372+schemaToFormula
374− Traced (Definitions Schema) ->
373+ :: Traced (Definitions Schema)
375− Traced Schema ->
374+ -> Traced Schema
376− (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
375+ -> (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
377schemaToFormula defs rs = runProcessM defs $ processSchema rs
376schemaToFormula defs rs = runProcessM defs $ processSchema rs
src/Data/OpenApi/Compare/Validate/Schema/Traced.hs+12−12
@@ -1,18 +1,18 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2
2
3module Data.OpenApi.Compare.Validate.Schema.Traced
3module Data.OpenApi.Compare.Validate.Schema.Traced
4− ( Step (..),
4+ ( Step (..)
5− tracedAllOf,
5+ , tracedAllOf
6− tracedAnyOf,
6+ , tracedAnyOf
7− tracedOneOf,
7+ , tracedOneOf
8− tracedItems,
8+ , tracedItems
9− tracedAdditionalProperties,
9+ , tracedAdditionalProperties
10− tracedDiscriminator,
10+ , tracedDiscriminator
11− tracedProperties,
11+ , tracedProperties
12− tracedConjunct,
12+ , tracedConjunct
13− PartitionLocation (..),
13+ , PartitionLocation (..)
14− PartitionChoice (..),
14+ , PartitionChoice (..)
15− Partition,
15+ , Partition
16 )
16 )
17where
17where
18
18
src/Data/OpenApi/Compare/Validate/Schema/TypedJson.hs+23−25
@@ -1,11 +1,11 @@
1module Data.OpenApi.Compare.Validate.Schema.TypedJson
1module Data.OpenApi.Compare.Validate.Schema.TypedJson
2− ( JsonType (..),
2+ ( JsonType (..)
3− describeJSONType,
3+ , describeJSONType
4− TypedValue (..),
4+ , TypedValue (..)
5− untypeValue,
5+ , untypeValue
6− ForeachType (..),
6+ , ForeachType (..)
7− foldType,
7+ , foldType
8− forType_,
8+ , forType_
9 )
9 )
10where
10where
11
11
@@ -88,26 +88,24 @@ forType_ :: Applicative m => (forall x. Typeable x => JsonType -> (ForeachType f
88forType_ k = getAp $ foldType (\ty proj -> Ap $ k ty proj)
88forType_ k = getAp $ foldType (\ty proj -> Ap $ k ty proj)
89
89
90broadcastType :: (forall x. Typeable x => f x) -> ForeachType f
90broadcastType :: (forall x. Typeable x => f x) -> ForeachType f
91−broadcastType k =
91+broadcastType k = ForeachType
92− ForeachType
93− { forNull = k
92+ { forNull = k
94− , forBoolean = k
93+ , forBoolean = k
95− , forNumber = k
94+ , forNumber = k
96− , forString = k
95+ , forString = k
97− , forArray = k
96+ , forArray = k
98− , forObject = k
97+ , forObject = k
99− }
98+ }
100
99
101zipType :: (forall x. Typeable x => f x -> g x -> h x) -> ForeachType f -> ForeachType g -> ForeachType h
100zipType :: (forall x. Typeable x => f x -> g x -> h x) -> ForeachType f -> ForeachType g -> ForeachType h
102−zipType k f1 f2 =
101+zipType k f1 f2 = ForeachType
103− ForeachType
104− { forNull = k (forNull f1) (forNull f2)
102+ { forNull = k (forNull f1) (forNull f2)
105− , forBoolean = k (forBoolean f1) (forBoolean f2)
103+ , forBoolean = k (forBoolean f1) (forBoolean f2)
106− , forNumber = k (forNumber f1) (forNumber f2)
104+ , forNumber = k (forNumber f1) (forNumber f2)
107− , forString = k (forString f1) (forString f2)
105+ , forString = k (forString f1) (forString f2)
108− , forArray = k (forArray f1) (forArray f2)
106+ , forArray = k (forArray f1) (forArray f2)
109− , forObject = k (forObject f1) (forObject f2)
107+ , forObject = k (forObject f1) (forObject f2)
110− }
108+ }
111
109
112instance (forall x. Lattice (f x)) => Lattice (ForeachType f) where
110instance (forall x. Lattice (f x)) => Lattice (ForeachType f) where
113 (\/) = zipType (\/)
111 (\/) = zipType (\/)
src/Data/OpenApi/Compare/Validate/SecurityRequirement.hs+8−9
@@ -2,7 +2,7 @@
2{-# OPTIONS_GHC -Wno-orphans #-}
2{-# OPTIONS_GHC -Wno-orphans #-}
3
3
4module Data.OpenApi.Compare.Validate.SecurityRequirement
4module Data.OpenApi.Compare.Validate.SecurityRequirement
5− ( Issue (..),
5+ ( Issue (..)
6 )
6 )
7where
7where
8
8
@@ -41,19 +41,18 @@ instance Subtree SecurityRequirement where
41 for (IOHM.toList $ getSecurityRequirement sec) $ \(key, scopes) ->
41 for (IOHM.toList $ getSecurityRequirement sec) $ \(key, scopes) ->
42 (,scopes) <$> lookupScheme key defs
42 (,scopes) <$> lookupScheme key defs
43 structuralMaybeWith
43 structuralMaybeWith
44− ( \pc' -> do
44+ (\pc' -> do
45− let ProdCons pScopes cScopes = fmap snd <$> pc'
45+ let ProdCons pScopes cScopes = fmap snd <$> pc'
46− unless (pScopes == cScopes) structuralIssue
46+ unless (pScopes == cScopes) structuralIssue
47− structuralList env $ fmap fst <$> pc'
47+ structuralList env $ fmap fst <$> pc'
48− pure ()
48+ pure ())
49− )
50 normalized
49 normalized
51 pure ()
50 pure ()
52 checkSemanticCompatibility env bhv' pc = do
51 checkSemanticCompatibility env bhv' pc = do
53 let schemes = getH @(ProdCons (Traced (Definitions SecurityScheme))) env
52 let schemes = getH @(ProdCons (Traced (Definitions SecurityScheme))) env
54 ( ProdCons pErrs cErrs
53 ( ProdCons pErrs cErrs
55− , (ProdCons pSchemes cSchemes) ::
54+ , (ProdCons pSchemes cSchemes)
56− ProdCons [(Behavior 'SecuritySchemeLevel, Traced SecurityScheme, [Text])]
55+ :: ProdCons [(Behavior 'SecuritySchemeLevel, Traced SecurityScheme, [Text])]
57 ) =
56 ) =
58 NE.unzip $
57 NE.unzip $
59 partitionEithers <$> do
58 partitionEithers <$> do
src/Data/OpenApi/Compare/Validate/Server.hs+9−10
@@ -1,7 +1,7 @@
1{-# OPTIONS_GHC -Wno-orphans #-}
1{-# OPTIONS_GHC -Wno-orphans #-}
2
2
3module Data.OpenApi.Compare.Validate.Server
3module Data.OpenApi.Compare.Validate.Server
4− ( Issue (..),
4+ ( Issue (..)
5 )
5 )
6where
6where
7
7
@@ -31,9 +31,9 @@ import Data.Traversable
31import Text.Pandoc.Builder
31import Text.Pandoc.Builder
32import Prelude as P
32import Prelude as P
33
33
34−tracedParsedServerUrlParts ::
34+tracedParsedServerUrlParts
35− Server ->
35+ :: Server
36− Either (Issue 'ServerLevel) ProcessedServer
36+ -> Either (Issue 'ServerLevel) ProcessedServer
37tracedParsedServerUrlParts s =
37tracedParsedServerUrlParts s =
38 let parsedUrl = parseServerUrl $ _serverUrl s
38 let parsedUrl = parseServerUrl $ _serverUrl s
39 lookupVar var = case IOHM.lookup var (_serverVariables s) of
39 lookupVar var = case IOHM.lookup var (_serverVariables s) of
@@ -63,12 +63,11 @@ instance Subtree [Server] where
63 pcServer
63 pcServer
64 <&> partitionEithers
64 <&> partitionEithers
65 . fmap
65 . fmap
66− ( \(Traced t s) ->
66+ (\(Traced t s) ->
67− let bhv = beh >>> step (InServer $ _serverUrl s)
67+ let bhv = beh >>> step (InServer $ _serverUrl s)
68− in case tracedParsedServerUrlParts s of
68+ in case tracedParsedServerUrlParts s of
69− Left e -> Left $ issueAt bhv e
69+ Left e -> Left $ issueAt bhv e
70− Right u -> Right (bhv, Traced (t >>> step (ServerStep $ _serverUrl s)) u)
70+ Right u -> Right (bhv, Traced (t >>> step (ServerStep $ _serverUrl s)) u))
71− )
72 . sequence
71 . sequence
73 sequenceA_ pErrs
72 sequenceA_ pErrs
74 sequenceA_ cErrs
73 sequenceA_ cErrs
src/Data/OpenApi/Compare/Validate/Sums.hs+11−12
@@ -1,25 +1,24 @@
1module Data.OpenApi.Compare.Validate.Sums
1module Data.OpenApi.Compare.Validate.Sums
2− ( checkSums,
2+ ( checkSums
3− )
4−where
3+ ) where
5
4
6import Data.Foldable
5import Data.Foldable
7import Data.Map.Strict (Map)
6import Data.Map.Strict (Map)
8import qualified Data.Map.Strict as M
7import qualified Data.Map.Strict as M
9import Data.OpenApi.Compare.Behavior
8import Data.OpenApi.Compare.Behavior
10−import Data.OpenApi.Compare.Paths
11import Data.OpenApi.Compare.Subtree
9import Data.OpenApi.Compare.Subtree
10+import Data.OpenApi.Compare.Paths
12
11
13−checkSums ::
12+checkSums
14− (Ord k, Issuable l) =>
13+ :: (Ord k, Issuable l)
15− Paths q r l ->
14+ => Paths q r l
16− (k -> Issue l) ->
15+ -> (k -> Issue l)
17− (k -> ProdCons t -> CompatFormula' q AnIssue r ()) ->
16+ -> (k -> ProdCons t -> CompatFormula' q AnIssue r ())
18− ProdCons (Map k t) ->
17+ -> ProdCons (Map k t)
19− CompatFormula' q AnIssue r ()
18+ -> CompatFormula' q AnIssue r ()
20checkSums xs noElt check (ProdCons p c) = for_ (M.toList p) $ \(key, prodElt) ->
19checkSums xs noElt check (ProdCons p c) = for_ (M.toList p) $ \(key, prodElt) ->
21 case M.lookup key c of
20 case M.lookup key c of
22 Nothing -> issueAt xs $ noElt key
21 Nothing -> issueAt xs $ noElt key
23 Just consElt ->
22 Just consElt ->
24 let sumElts = ProdCons prodElt consElt
23 let sumElts = ProdCons prodElt consElt
25− in check key sumElts
24+ in check key sumElts
src/Data/OpenUnion/Extra.hs+5−5
@@ -1,7 +1,7 @@
1module Data.OpenUnion.Extra
1module Data.OpenUnion.Extra
2− ( (@@>),
2+ ( (@@>)
3− TryLiftUnion (..),
3+ , TryLiftUnion (..)
4− pattern SingletonUnion,
4+ , pattern SingletonUnion
5 )
5 )
6where
6where
7
7
@@ -18,8 +18,8 @@ instance TryLiftUnion '[] where
18 tryLiftUnion _ = empty
18 tryLiftUnion _ = empty
19
19
20instance
20instance
21− (Typeable y, SubList ys (y : ys), TryLiftUnion ys) =>
21+ (Typeable y, SubList ys (y : ys), TryLiftUnion ys)
22− TryLiftUnion (y ': ys)
22+ => TryLiftUnion (y ': ys)
23 where
23 where
24 tryLiftUnion (x :: x) = case eqT @x @y of
24 tryLiftUnion (x :: x) = case eqT @x @y of
25 Nothing -> reUnion <$> tryLiftUnion @ys x
25 Nothing -> reUnion <$> tryLiftUnion @ys x
test/Spec/Golden/Extra.hs+42−46
@@ -1,8 +1,8 @@
1module Spec.Golden.Extra
1module Spec.Golden.Extra
2− ( getGoldenInputs,
2+ ( getGoldenInputs
3− getGoldenInputsUniform,
3+ , getGoldenInputsUniform
4− goldenInputsTree,
4+ , goldenInputsTree
5− goldenInputsTreeUniform,
5+ , goldenInputsTreeUniform
6 )
6 )
7where
7where
8
8
@@ -19,12 +19,12 @@ data TestInput t
19 | TestInputLeaf TestName t FilePath
19 | TestInputLeaf TestName t FilePath
20 deriving stock (Functor)
20 deriving stock (Functor)
21
21
22−getGoldenInputs ::
22+getGoldenInputs
23− (Each s t (FilePath, FilePath -> IO a) a) =>
23+ :: (Each s t (FilePath, FilePath -> IO a) a)
24− TestName ->
24+ => TestName
25− FilePath ->
25+ -> FilePath
26− s ->
26+ -> s
27− IO (TestInput t)
27+ -> IO (TestInput t)
28getGoldenInputs name filepath inp = do
28getGoldenInputs name filepath inp = do
29 dirs' <- listDirectory filepath >>= filterM (doesDirectoryExist . (filepath </>))
29 dirs' <- listDirectory filepath >>= filterM (doesDirectoryExist . (filepath </>))
30 case dirs' of
30 case dirs' of
@@ -39,34 +39,32 @@ getGoldenInputs name filepath inp = do
39 TestInputNode name
39 TestInputNode name
40 <$> forM dirs (\dir -> getGoldenInputs dir (filepath </> dir) inp)
40 <$> forM dirs (\dir -> getGoldenInputs dir (filepath </> dir) inp)
41
41
42−getGoldenInputsUniform ::
42+getGoldenInputsUniform
43− (Each t h (FilePath, FilePath -> IO a) a) =>
43+ :: (Each t h (FilePath, FilePath -> IO a) a)
44− (Each s t FilePath (FilePath, FilePath -> IO a)) =>
44+ => (Each s t FilePath (FilePath, FilePath -> IO a))
45− TestName ->
45+ => TestName
46− (FilePath -> IO a) ->
46+ -> (FilePath -> IO a)
47− FilePath ->
47+ -> FilePath
48− s ->
48+ -> s
49− IO (TestInput h)
49+ -> IO (TestInput h)
50getGoldenInputsUniform name f filepath inp = getGoldenInputs name filepath $ inp & each %~ (,f)
50getGoldenInputsUniform name f filepath inp = getGoldenInputs name filepath $ inp & each %~ (,f)
51
51
52−goldenInputsTree ::
52+goldenInputsTree
53− (Each s t (FilePath, FilePath -> IO a) a) =>
53+ :: (Each s t (FilePath, FilePath -> IO a) a)
54− TestName ->
54+ => TestName
55− -- | Root path
55+ -> FilePath -- ^ Root path
56− FilePath ->
57− -- | Name of golden file
56+ -> FilePath -- ^ Name of golden file
58− FilePath ->
57+ -> s
59− s ->
60− (t -> IO BSL.ByteString) ->
58+ -> (t -> IO BSL.ByteString)
61− IO TestTree
59+ -> IO TestTree
62goldenInputsTree name filepath golden inp f = do
60goldenInputsTree name filepath golden inp f = do
63 runTestInputTree golden f <$> getGoldenInputs name filepath inp
61 runTestInputTree golden f <$> getGoldenInputs name filepath inp
64
62
65−runTestInputTree ::
63+runTestInputTree
66− FilePath ->
64+ :: FilePath
67− (t -> IO BSL.ByteString) ->
65+ -> (t -> IO BSL.ByteString)
68− TestInput t ->
66+ -> TestInput t
69− TestTree
67+ -> TestTree
70runTestInputTree golden f (TestInputNode name rest) =
68runTestInputTree golden f (TestInputNode name rest) =
71 testGroup name (runTestInputTree golden f <$> rest)
69 testGroup name (runTestInputTree golden f <$> rest)
72runTestInputTree golden f (TestInputLeaf name t path) =
70runTestInputTree golden f (TestInputLeaf name t path) =
@@ -76,18 +74,16 @@ runTestInputTree golden f (TestInputLeaf name t path) =
76 (path </> golden)
74 (path </> golden)
77 (f t)
75 (f t)
78
76
79−goldenInputsTreeUniform ::
77+goldenInputsTreeUniform
80− ( Each t h (FilePath, FilePath -> IO a) a
78+ :: ( Each t h (FilePath, FilePath -> IO a) a
81− , Each s t FilePath (FilePath, FilePath -> IO a)
79+ , Each s t FilePath (FilePath, FilePath -> IO a)
82− ) =>
80+ )
83− String ->
81+ => String
84− -- | Root path
82+ -> FilePath -- ^ Root path
85− FilePath ->
86− -- | Name of golden file
83+ -> FilePath -- ^ Name of golden file
87− FilePath ->
84+ -> s
88− s ->
89− (FilePath -> IO a) ->
85+ -> (FilePath -> IO a)
90− (h -> IO BSL.ByteString) ->
86+ -> (h -> IO BSL.ByteString)
91− IO TestTree
87+ -> IO TestTree
92goldenInputsTreeUniform name filepath golden inp h =
88goldenInputsTreeUniform name filepath golden inp h =
93 goldenInputsTree name filepath golden (inp & each %~ (,h))
89 goldenInputsTree name filepath golden (inp & each %~ (,h))
test/Spec/Golden/TraceTree.hs+2−4
@@ -12,7 +12,6 @@ import Data.OpenApi.Compare.Validate.OpenApi ()
12import Data.Text (Text)
12import Data.Text (Text)
13import qualified Data.Text.Encoding as T
13import qualified Data.Text.Encoding as T
14import qualified Data.Yaml as Yaml
14import qualified Data.Yaml as Yaml
15−import Paths_compaREST
16import Spec.Golden.Extra
15import Spec.Golden.Extra
17import Test.Tasty (TestTree, testGroup)
16import Test.Tasty (TestTree, testGroup)
18import Text.Pandoc.Builder
17import Text.Pandoc.Builder
@@ -23,11 +22,10 @@ import Prelude hiding (id, (.))
23
22
24tests :: IO TestTree
23tests :: IO TestTree
25tests = do
24tests = do
26− dir <- getDataDir
27 traceTreeTests <-
25 traceTreeTests <-
28 goldenInputsTreeUniform
26 goldenInputsTreeUniform
29 "TraceTree"
27 "TraceTree"
30− dir
28+ "test/golden/common"
31 "trace-tree.yaml"
29 "trace-tree.yaml"
32 ("a.yaml", "b.yaml")
30 ("a.yaml", "b.yaml")
33 Yaml.decodeFileThrow
31 Yaml.decodeFileThrow
@@ -36,7 +34,7 @@ tests = do
36 reportTests <-
34 reportTests <-
37 goldenInputsTreeUniform
35 goldenInputsTreeUniform
38 "Report"
36 "Report"
39− dir
37+ "test/golden/common"
40 "report.md"
38 "report.md"
41 ("a.yaml", "b.yaml")
39 ("a.yaml", "b.yaml")
42 Yaml.decodeFileThrow
40 Yaml.decodeFileThrow