git.iko.soy/typeable/compaREST
on master help sign in
229 files changed+18293−3023
since splitsnapshots
unifiedsplit
.github/actions/common_setup/action.yaml+42 .github/workflows/github-actions-image.yaml+290 .github/workflows/haskell.yml−55 .github/workflows/remove-artifacts.yaml−17 .gitignore+1 CHANGELOG.md+7−3 LICENSE+1−1 README.md+326−4 action.yaml+48 app/Data/OpenApi/Compare/Options.hs+135 app/FormatHeuristic.hs+80−54 app/Main.hs+29−22 benchmarks/README.md+27 benchmarks/atlassian/addDist.patch+10 benchmarks/atlassian/yarn.lock+4918 benchmarks/default.nix+181 benchmarks/nix/sources.json+92 benchmarks/nix/sources.nix+171 benchmarks/oasdiff/gomod2nix.toml+135 benchmarks/openapitools/mavenix.lock+3511 benchmarks/report.md+41 ci/policeman.nix+4 compaREST.cabal+227 css/awsm.min.css+1 default.nix+125 docs/Development_guide.md+149 docs/Integration_guide.md+49 docs/Releasing.md+15 docs/User_guide.md+51 docs/img/github-action-report.png docs/img/pre-release-artifacts.png docs/img/pre-release-ci.png docs/img/pre-release.png fourmolu.yaml+8 github-action/CompaREST/GitHub/API.hs+86 github-action/CompaREST/GitHub/Action/Config.hs+47 github-action/Control/Monad/Freer/GitHub.hs+27 github-action/GitHub/Data/Checks.hs+173 github-action/GitHub/Endpoints/Checks.hs+12 github-action/Main.hs+72 nix/ci.nix+11 nix/diff-yaml.nix+20 nix/shell.nix+11 nix/sources.json+50 nix/sources.nix+174 nix/yq.nix+26 openapi-diff.cabal−179 scripts/diff-yaml+35 src/Data/HList.hs+37−7 src/Data/OpenApi/Compare/Behavior.hs+124 src/OpenAPI/Checker/Common.hs → src/Data/OpenApi/Compare/Common.hs+2−2 src/OpenAPI/Checker/Formula.hs → src/Data/OpenApi/Compare/Formula.hs+35−25 src/Data/OpenApi/Compare/Memo.hs+164 src/OpenAPI/Checker/Orphans.hs → src/Data/OpenApi/Compare/Orphans.hs+1−1 src/OpenAPI/Checker/Paths.hs → src/Data/OpenApi/Compare/Paths.hs+13−16 src/OpenAPI/Checker/PathsPrefixTree.hs → src/Data/OpenApi/Compare/PathsPrefixTree.hs+120−55 src/OpenAPI/Checker/References.hs → src/Data/OpenApi/Compare/References.hs+18−19 src/Data/OpenApi/Compare/Report.hs+399 src/Data/OpenApi/Compare/Report/Html/Template.hs+39 src/Data/OpenApi/Compare/Report/Jet.hs+67 src/Data/OpenApi/Compare/Run.hs+31 src/Data/OpenApi/Compare/Subtree.hs+364 src/OpenAPI/Checker/Validate/Header.hs → src/Data/OpenApi/Compare/Validate/Header.hs+15−11 src/OpenAPI/Checker/Validate/Link.hs → src/Data/OpenApi/Compare/Validate/Link.hs+7−7 src/OpenAPI/Checker/Validate/MediaTypeObject.hs → src/Data/OpenApi/Compare/Validate/MediaTypeObject.hs+41−35 src/OpenAPI/Checker/Validate/OAuth2Flows.hs → src/Data/OpenApi/Compare/Validate/OAuth2Flows.hs+59−46 src/OpenAPI/Checker/Validate/OpenApi.hs → src/Data/OpenApi/Compare/Validate/OpenApi.hs+29−26 src/OpenAPI/Checker/Validate/Operation.hs → src/Data/OpenApi/Compare/Validate/Operation.hs+85−97 src/OpenAPI/Checker/Validate/Param.hs → src/Data/OpenApi/Compare/Validate/Param.hs+63−48 src/OpenAPI/Checker/Validate/PathFragment.hs → src/Data/OpenApi/Compare/Validate/PathFragment.hs+28−24 src/Data/OpenApi/Compare/Validate/Products.hs+48 src/OpenAPI/Checker/Validate/RequestBody.hs → src/Data/OpenApi/Compare/Validate/RequestBody.hs+21−16 src/OpenAPI/Checker/Validate/Responses.hs → src/Data/OpenApi/Compare/Validate/Responses.hs+32−27 src/Data/OpenApi/Compare/Validate/Schema.hs+398 src/Data/OpenApi/Compare/Validate/Schema/DNF.hs+101 src/Data/OpenApi/Compare/Validate/Schema/Issues.hs+321 src/Data/OpenApi/Compare/Validate/Schema/JsonFormula.hs+237 src/Data/OpenApi/Compare/Validate/Schema/Partition.hs+320 src/Data/OpenApi/Compare/Validate/Schema/Process.hs+375 src/Data/OpenApi/Compare/Validate/Schema/Traced.hs+115 src/Data/OpenApi/Compare/Validate/Schema/TypedJson.hs+120 src/OpenAPI/Checker/Validate/SecurityRequirement.hs → src/Data/OpenApi/Compare/Validate/SecurityRequirement.hs+15−14 src/OpenAPI/Checker/Validate/SecurityScheme.hs → src/Data/OpenApi/Compare/Validate/SecurityScheme.hs+8−8 src/OpenAPI/Checker/Validate/Server.hs → src/Data/OpenApi/Compare/Validate/Server.hs+34−26 src/Data/OpenApi/Compare/Validate/Sums.hs+25 src/Data/OpenUnion/Extra.hs+43 src/OpenAPI/Checker/Behavior.hs−63 src/OpenAPI/Checker/Memo.hs−126 src/OpenAPI/Checker/Options.hs−65 src/OpenAPI/Checker/Report.hs−136 src/OpenAPI/Checker/Subtree.hs−314 src/OpenAPI/Checker/Subtree/Deriving.hs−6 src/OpenAPI/Checker/Validate/Products.hs−49 src/OpenAPI/Checker/Validate/Schema.hs−1187 src/OpenAPI/Checker/Validate/Sums.hs−24 stack.yaml+23−1 stack.yaml.lock+40−5 test/README.md+1−1 test/Spec.hs+1−1 test/Spec/Golden/Extra.hs+49−45 test/Spec/Golden/TraceTree.hs+8−21 test/golden/common/bad-oneof-unchanged/a.yaml+39 test/golden/common/bad-oneof-unchanged/b.yaml+39 test/golden/common/bad-oneof-unchanged/report.md+19 test/golden/common/bad-oneof-unchanged/trace-tree.yaml+18 test/golden/common/enum-added/a.yaml+25 test/golden/common/enum-added/b.yaml+25 test/golden/common/enum-added/report.md+33 test/golden/common/enum-added/trace-tree.yaml+14 test/golden/common/enum-anyof/report.md+5−1 test/golden/common/enum-anyof/trace-tree.yaml+2−1 test/golden/common/id/report.md+5−1 test/golden/common/id/trace-tree.yaml+2−1 test/golden/common/json/recursive/report.md+5−1 test/golden/common/json/recursive/trace-tree.yaml+2−1 test/golden/common/maximum-lowered/report.md+22−4 test/golden/common/maximum-lowered/trace-tree.yaml+9−1 test/golden/common/pathItem/operation/parameters/allowEmptyValue/reset/report.md+11−3 test/golden/common/pathItem/operation/parameters/allowEmptyValue/reset/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/parameters/allowEmptyValue/set/report.md+13−1 test/golden/common/pathItem/operation/parameters/allowEmptyValue/set/trace-tree.yaml+5−1 test/golden/common/pathItem/operation/parameters/change/report.md+25−5 test/golden/common/pathItem/operation/parameters/change/trace-tree.yaml+8−2 test/golden/common/pathItem/operation/parameters/required/false/add/report.md+5−1 test/golden/common/pathItem/operation/parameters/required/false/add/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/parameters/required/false/del/report.md+5−1 test/golden/common/pathItem/operation/parameters/required/false/del/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/parameters/required/reset/report.md+13−1 test/golden/common/pathItem/operation/parameters/required/reset/trace-tree.yaml+5−1 test/golden/common/pathItem/operation/parameters/required/set/report.md+11−3 test/golden/common/pathItem/operation/parameters/required/set/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/parameters/required/true/add/report.md+10−2 test/golden/common/pathItem/operation/parameters/required/true/add/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/parameters/required/true/del/report.md+11−1 test/golden/common/pathItem/operation/parameters/required/true/del/trace-tree.yaml+4−1 test/golden/common/pathItem/operation/requestBody/mediaTypeObject/add/report.md+13−1 test/golden/common/pathItem/operation/requestBody/mediaTypeObject/add/trace-tree.yaml+5−1 test/golden/common/pathItem/operation/requestBody/mediaTypeObject/change/report.md+22−4 test/golden/common/pathItem/operation/requestBody/mediaTypeObject/change/trace-tree.yaml+9−2 test/golden/common/pathItem/operation/requestBody/mediaTypeObject/del/report.md+11−4 test/golden/common/pathItem/operation/requestBody/mediaTypeObject/del/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/requestBody/required/reset/report.md+13−1 test/golden/common/pathItem/operation/requestBody/required/reset/trace-tree.yaml+5−1 test/golden/common/pathItem/operation/requestBody/required/set/report.md+11−3 test/golden/common/pathItem/operation/requestBody/required/set/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/responses/add/report.md+10−2 test/golden/common/pathItem/operation/responses/add/trace-tree.yaml+3−2 test/golden/common/pathItem/operation/responses/change/headers/mandatory/add/report.md+13−1 test/golden/common/pathItem/operation/responses/change/headers/mandatory/add/trace-tree.yaml+5−1 test/golden/common/pathItem/operation/responses/change/headers/mandatory/del/report.md+11−3 test/golden/common/pathItem/operation/responses/change/headers/mandatory/del/trace-tree.yaml+3−2 test/golden/common/pathItem/operation/responses/change/headers/optional/add/report.md+5−1 test/golden/common/pathItem/operation/responses/change/headers/optional/add/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/responses/change/headers/optional/del/report.md+5−1 test/golden/common/pathItem/operation/responses/change/headers/optional/del/trace-tree.yaml+2−1 test/golden/common/pathItem/operation/responses/change/mediaTypeObject/add/report.md+11−4 test/golden/common/pathItem/operation/responses/change/mediaTypeObject/add/trace-tree.yaml+3−2 test/golden/common/pathItem/operation/responses/change/mediaTypeObject/change/report.md+22−4 test/golden/common/pathItem/operation/responses/change/mediaTypeObject/change/trace-tree.yaml+9−2 test/golden/common/pathItem/operation/responses/change/mediaTypeObject/del/report.md+13−1 test/golden/common/pathItem/operation/responses/change/mediaTypeObject/del/trace-tree.yaml+5−1 test/golden/common/pathItem/operation/responses/del/report.md+11−1 test/golden/common/pathItem/operation/responses/del/trace-tree.yaml+4−1 test/golden/common/property-removed-additional/a.yaml+32 test/golden/common/property-removed-additional/b.yaml+29 test/golden/common/property-removed-additional/report.md+39 test/golden/common/property-removed-additional/trace-tree.yaml+22 test/golden/common/property-removed/report.md+15−7 test/golden/common/property-removed/trace-tree.yaml+18−3 test/golden/common/property-required/report.md+22−4 test/golden/common/property-required/trace-tree.yaml+11−2 test/golden/common/random-example/a.yaml+56 test/golden/common/random-example/b.yaml+58 test/golden/common/random-example/report.md+71 test/golden/common/random-example/trace-tree.yaml+48 test/golden/common/recursive/a.yaml+6 test/golden/common/recursive/b.yaml+6 test/golden/common/recursive/report.md+33−1 test/golden/common/recursive/trace-tree.yaml+26−1 test/golden/common/security-scheme/report.md+26−8 test/golden/common/security-scheme/trace-tree.yaml+6−1 test/golden/common/servers/report.md+22−6 test/golden/common/servers/trace-tree.yaml+6−1 test/golden/common/tuple-items/heterogeneous-component-mismatch/a.yaml+28 test/golden/common/tuple-items/heterogeneous-component-mismatch/b.yaml+28 test/golden/common/tuple-items/heterogeneous-component-mismatch/report.md+37 test/golden/common/tuple-items/heterogeneous-component-mismatch/trace-tree.yaml+30 test/golden/common/tuple-items/heterogeneous-length-mismatch/a.yaml+29 test/golden/common/tuple-items/heterogeneous-length-mismatch/b.yaml+28 test/golden/common/tuple-items/heterogeneous-length-mismatch/report.md+21 test/golden/common/tuple-items/heterogeneous-length-mismatch/trace-tree.yaml+26 test/golden/common/tuple-items/homogeneous-component-mismatch/a.yaml+28 test/golden/common/tuple-items/homogeneous-component-mismatch/b.yaml+29 test/golden/common/tuple-items/homogeneous-component-mismatch/report.md+45 test/golden/common/tuple-items/homogeneous-component-mismatch/trace-tree.yaml+34 test/golden/common/tuple-items/homogeneous-length-mismatch/a.yaml+56 test/golden/common/tuple-items/homogeneous-length-mismatch/b.yaml+67 test/golden/common/tuple-items/homogeneous-length-mismatch/report.md+73 test/golden/common/tuple-items/homogeneous-length-mismatch/trace-tree.yaml+52 test/golden/common/tuple-items/homogeneous-vector/a.yaml+28 test/golden/common/tuple-items/homogeneous-vector/b.yaml+29 test/golden/common/tuple-items/homogeneous-vector/report.md+5 test/golden/common/tuple-items/homogeneous-vector/trace-tree.yaml+2 test/golden/common/type-changing/a.yaml+113 test/golden/common/type-changing/b.yaml+108 test/golden/common/type-changing/report.md+105 test/golden/common/type-changing/trace-tree.yaml+60 test/golden/common/unguarded-recursive/a.yaml → test/golden/common/unguarded-recursive/basic/a.yaml test/golden/common/unguarded-recursive/b.yaml → test/golden/common/unguarded-recursive/basic/b.yaml test/golden/common/unguarded-recursive/basic/report.md+13 test/golden/common/unguarded-recursive/basic/trace-tree.yaml+12 test/golden/common/unguarded-recursive/report.md−5 test/golden/common/unguarded-recursive/silent/a.yaml+25 test/golden/common/unguarded-recursive/silent/b.yaml+19 test/golden/common/unguarded-recursive/silent/report.md+15 test/golden/common/unguarded-recursive/silent/trace-tree.yaml+16 test/golden/common/unguarded-recursive/trace-tree.yaml−6 test/golden/common/variant-added/a.yaml+39 test/golden/common/variant-added/b.yaml+46 test/golden/common/variant-added/report.md+25 test/golden/common/variant-added/trace-tree.yaml+16 test/golden/common/variant-changed/a.yaml+39 test/golden/common/variant-changed/b.yaml+39 test/golden/common/variant-changed/report.md+45 test/golden/common/variant-changed/trace-tree.yaml+34 test/golden/common/variant-deep-changed/a.yaml+47 test/golden/common/variant-deep-changed/b.yaml+47 test/golden/common/variant-deep-changed/report.md+45 test/golden/common/variant-deep-changed/trace-tree.yaml+34
.github/actions/common_setup/action.yamlnew file+42
@@ -0,0 +1,42 @@
1+name: "Common setup"
2+description: "Common setup steps"
3+inputs:
4+ authToken:
5+ description: "Cachix auth token"
6+ required: true
7+runs:
8+ using: "composite"
9+ 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
33+ uses: cachix/install-nix-action@v27
34+ with:
35+ extra_nix_config: |
36+ system-features = kvm
37+ 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/
39+ - uses: cachix/cachix-action@v15
40+ with:
41+ name: typeable
42+ authToken: "${{ inputs.authToken }}"
.github/workflows/github-actions-image.yamlnew file+290
@@ -0,0 +1,290 @@
1+name: Github Action Docker Image
2+
3+on:
4+ push:
5+ branches: [master]
6+ pull_request:
7+ branches: [master]
8+ release:
9+ types: [prereleased]
10+
11+jobs:
12+# check-formatting:
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+ check_versions:
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: Check library version
41+ if: github.event_name == 'release'
42+ run: |
43+ if [ "$(awk -F ':' '/^version/ {gsub(/ /, "", $2); print $2}' compaREST.cabal)" != "${{ github.event.release.tag_name }}" ]; then
44+ echo "::error file=compaREST.cabal::Library version does not match release version."
45+ exit 1
46+ fi
47+
48+ - name: Check docker tag
49+ if: github.event_name == 'release'
50+ run: |
51+ if [ "$(yq eval '.runs.image' action.yaml | awk -F ':' '{print $NF}')" != "${{ github.event.release.tag_name }}" ]; then
52+ echo "::error file=action.yaml::Action docker tag does not match release tag."
53+ exit 1
54+ fi
55+
56+ - name: Check changelog
57+ if: github.event_name == 'release'
58+ run: |
59+ if ! grep '^## ${{ github.event.release.tag_name }}$' CHANGELOG.md; then
60+ echo "::error file=CHANGELOG.md::CHANGELOG.md does not contain an entry for this release."
61+ exit 1
62+ fi
63+
64+ Linux:
65+ needs: check_versions
66+ runs-on: ubuntu-latest
67+ steps:
68+ - uses: actions/checkout@v2
69+ with:
70+ submodules: recursive
71+
72+ - name: Common setup
73+ uses: ./.github/actions/common_setup
74+ with:
75+ authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
76+
77+ - name: Test
78+ shell: bash
79+ run: |
80+ $(nix-build -A test -j auto --no-out-link)/bin/compaREST-tests
81+
82+ - name: Build Linux static binary
83+ shell: bash
84+ run: |
85+ cp $(nix-build -A compaRESTStaticBin -j auto --no-out-link)/bin/compaREST compaREST
86+
87+ - name: Upload compaREST Linux Binary
88+ uses: actions/upload-artifact@v2
89+ with:
90+ name: compaREST-Linux
91+ path: compaREST
92+
93+ - name: Build Docker Images
94+ shell: bash
95+ run: |
96+ cp $(nix-build -A compaRESTGithubAction -j auto --no-out-link) compaREST-Github-Action-image.tar.gz
97+ cp $(nix-build -A compaRESTImage -j auto --no-out-link) compaREST-image.tar.gz
98+
99+ - name: Upload compaREST Docker Github Action Image
100+ uses: actions/upload-artifact@v2
101+ with:
102+ name: compaREST Github Action Docker Image
103+ path: compaREST-Github-Action-image.tar.gz
104+
105+ - name: Upload compaREST Docker Image
106+ uses: actions/upload-artifact@v2
107+ with:
108+ name: compaREST Docker Image
109+ path: compaREST-image.tar.gz
110+
111+ - name: Login to DockerHub
112+ uses: docker/login-action@v1.10.0
113+ with:
114+ username: ${{ secrets.DOCKER_HUB_USERNAME }}
115+ password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
116+
117+ - name: Push Nightly Docker Images to DockerHub
118+ if: github.ref == 'refs/heads/master' && github.event_name == 'push'
119+ shell: bash
120+ run: |
121+ skopeo copy docker-archive:$(nix-build -A compaRESTGithubAction -j auto --no-out-link) docker://typeable/comparest-github-action:nightly
122+ skopeo copy docker-archive:$(nix-build -A compaRESTImage -j auto --no-out-link) docker://typeable/comparest:nightly
123+
124+ - name: Push Release Docker Images to DockerHub
125+ if: github.event_name == 'release'
126+ shell: bash
127+ run: |
128+ skopeo copy docker-archive:$(nix-build -A compaRESTGithubAction -j auto --no-out-link) docker://typeable/comparest-github-action:${{ github.event.release.tag_name }}
129+ skopeo copy docker-archive:$(nix-build -A compaRESTImage -j auto --no-out-link) docker://typeable/comparest:${{ github.event.release.tag_name }}
130+
131+ - name: Zip Release Assets
132+ if: github.event_name == 'release'
133+ shell: bash
134+ run: |
135+ zip compaREST-Linux-x86.zip compaREST
136+
137+ - name: Upload compaREST Github Action Docker Image to release
138+ if: github.event_name == 'release'
139+ uses: svenstaro/upload-release-action@2.2.1
140+ with:
141+ repo_token: ${{ secrets.GITHUB_TOKEN }}
142+ file: compaREST-Github-Action-image.tar.gz
143+ tag: ${{ github.ref }}
144+
145+ - name: Upload compaREST Docker Image to release
146+ if: github.event_name == 'release'
147+ uses: svenstaro/upload-release-action@2.2.1
148+ with:
149+ repo_token: ${{ secrets.GITHUB_TOKEN }}
150+ file: compaREST-image.tar.gz
151+ tag: ${{ github.ref }}
152+
153+ - name: Upload compaREST binary – Linux – x86 to release
154+ if: github.event_name == 'release'
155+ uses: svenstaro/upload-release-action@2.2.1
156+ with:
157+ repo_token: ${{ secrets.GITHUB_TOKEN }}
158+ file: compaREST-Linux-x86.zip
159+ tag: ${{ github.ref }}
160+
161+ dist:
162+ needs: [check_versions, Linux]
163+ runs-on: ubuntu-latest
164+ steps:
165+ - uses: actions/checkout@v2
166+ with:
167+ submodules: recursive
168+
169+ - name: Common setup
170+ uses: ./.github/actions/common_setup
171+ with:
172+ authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
173+
174+ - name: Cache
175+ uses: actions/cache@v1
176+ with:
177+ path: |
178+ ~/.stack
179+ .stack-work
180+ key: ${{ runner.os }}-stack-${{ hashFiles('stack.yaml') }}-${{ hashFiles('**.cabal') }}
181+ restore-keys: |
182+ ${{ runner.os }}-stack-${{ hashFiles('stack.yaml') }}
183+ ${{ runner.os }}-stack
184+
185+ - name: Upgrade stack
186+ shell: bash
187+ # Needed for Hackage token authorization
188+ run: stack upgrade --git
189+
190+ - name: Build dist
191+ run: |
192+ stack sdist --pvp-bounds both
193+ echo "distPath=$(stack path | awk -F ": " '/dist-dir/ {print $2}')" >> $GITHUB_ENV
194+
195+ - name: Upload compaREST sources artifact
196+ uses: actions/upload-artifact@v2
197+ with:
198+ name: compaREST sources
199+ path: ${{ env.distPath }}/*.tar.gz
200+
201+ - name: Upload compaREST sources to release
202+ if: github.event_name == 'release'
203+ uses: svenstaro/upload-release-action@2.2.1
204+ with:
205+ repo_token: ${{ secrets.GITHUB_TOKEN }}
206+ file_glob: true
207+ file: ${{ env.distPath }}/*.tar.gz
208+ tag: ${{ github.ref }}
209+
210+ - name: Publish compaREST candidate to Hackage
211+ shell: bash
212+ if: github.event_name == 'release'
213+ env:
214+ HACKAGE_KEY: ${{ secrets.HACKAGE_KEY }}
215+ run: |
216+ stack upload --pvp-bounds both --candidate .
217+
218+ macOS:
219+ needs: check_versions
220+ runs-on: macos-latest
221+ steps:
222+ - uses: actions/checkout@v2
223+ with:
224+ submodules: recursive
225+
226+ - name: Common setup
227+ uses: ./.github/actions/common_setup
228+ with:
229+ authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
230+
231+ - name: Build macOS binary bundle
232+ run: |
233+ cp -LR $(nix-build -A macOSCompaRESTBundle -j auto --no-out-link) compaREST
234+
235+ - name: Upload macOS compaREST bundle
236+ uses: actions/upload-artifact@v2
237+ with:
238+ name: compaREST binary – macOS – x86
239+ path: compaREST
240+
241+ - name: Zip Release Assets
242+ if: github.event_name == 'release'
243+ shell: bash
244+ run: |
245+ zip -r compaREST-macOS-x86.zip compaREST
246+
247+ - name: Upload compaREST binary – macOS – x86 to release
248+ if: github.event_name == 'release'
249+ uses: svenstaro/upload-release-action@2.2.1
250+ with:
251+ repo_token: ${{ secrets.GITHUB_TOKEN }}
252+ file: compaREST-macOS-x86.zip
253+ tag: ${{ github.ref }}
254+
255+# Linux-Windows:
256+# needs: check_versions
257+# runs-on: ubuntu-latest
258+# steps:
259+# - uses: actions/checkout@v2
260+# with:
261+# submodules: recursive
262+#
263+# - name: Common setup
264+# uses: ./.github/actions/common_setup
265+# with:
266+# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
267+#
268+# - name: Build Windows binary
269+# run: |
270+# cp -LR $(nix-build -A WindowsCompaRESTBin -j auto --no-out-link)/bin compaREST
271+#
272+# - name: Upload Windows compaREST bundle
273+# uses: actions/upload-artifact@v2
274+# with:
275+# name: compaREST binary – Windows
276+# path: compaREST
277+#
278+# - name: Zip Release Assets
279+# if: github.event_name == 'release'
280+# shell: bash
281+# run: |
282+# zip -r compaREST-Windows.zip compaREST
283+#
284+# - name: Upload compaREST binary – Windows to release
285+# if: github.event_name == 'release'
286+# uses: svenstaro/upload-release-action@2.2.1
287+# with:
288+# repo_token: ${{ secrets.GITHUB_TOKEN }}
289+# file: compaREST-Windows.zip
290+# tag: ${{ github.ref }}
.github/workflows/haskell.ymldeleted−55
@@ -1,55 +0,0 @@
1−name: Haskell CI
2−
3−on:
4− push:
5− branches: [master]
6− pull_request:
7− branches: [master]
8−
9−jobs:
10− linux-build:
11− runs-on: ubuntu-latest
12−
13− steps:
14− - uses: actions/checkout@v2
15− - uses: haskell/actions/setup@v1
16− with:
17− enable-stack: true
18− stack-no-global: true
19− stack-version: "latest"
20− - name: Cache
21− uses: actions/cache@v1
22− with:
23− path: ~/.stack
24− key: ${{ runner.os }}-build-stack-${{ hashFiles('**/stack.yaml') }}-${{ hashFiles('**/*.cabal') }}
25− restore-keys: |
26− ${{ runner.os }}-build-stack-${{ hashFiles('**/stack.yaml') }}
27− ${{ runner.os }}-build-stack-
28− - name: Build
29− run: stack build --ghc-options="-O3 -j" --local-bin-path out --copy-bins --flag openapi-diff:Static
30− - name: Test
31− run: stack test --test-arguments='--hide-successes --no-create'
32− - name: Upload artifact
33− uses: actions/upload-artifact@v2
34− with:
35− name: openapi-diff-linux
36− path: out/openapi-diff
37− release:
38− name: "Release"
39− if: github.ref == 'refs/heads/master'
40− runs-on: "ubuntu-latest"
41− needs: [linux-build]
42− steps:
43− - uses: actions/download-artifact@v2
44− - name: Zip
45− run: |
46− chmod +x openapi-diff-linux/openapi-diff
47− zip openapi-diff-linux openapi-diff-linux/openapi-diff
48− - uses: "marvinpinto/action-automatic-releases@latest"
49− with:
50− repo_token: "${{ secrets.GITHUB_TOKEN }}"
51− automatic_release_tag: "latest"
52− prerelease: false
53− title: "Pre-Release"
54− files: |
55− *.zip
.github/workflows/remove-artifacts.yamldeleted−17
@@ -1,17 +0,0 @@
1−name: Remove old artifacts
2−
3−on:
4− schedule:
5− - cron: '0 0 * * *'
6−jobs:
7− remove-old-artifacts:
8− runs-on: ubuntu-latest
9− timeout-minutes: 10
10−
11− steps:
12− - name: Remove old artifacts
13− uses: c-hive/gha-remove-artifacts@v1
14− with:
15− age: '7 days'
16− skip-tags: true
17− skip-recent: 10
.gitignore+1
@@ -2,3 +2,4 @@
22TAGS
33.vscode
44.dir-locals.el
5+test/golden/common/prod
CHANGELOG.md+7−3
@@ -1,9 +1,13 @@
11# Changelog
22
3−`openapi-diff` uses [PVP Versioning][1].
3+`compaREST` uses [PVP Versioning][1].
44
5−## 0.0.0.0
5+## 0.1.0.1
66
7−* Initially created.
7+* Fixed an issue related to empty commit SHAs in GitHub Actions.
8+
9+## 0.1.0.0
10+
11+* Initial release.
812
913[1]: https://pvp.haskell.org
LICENSE+1−1
@@ -1,6 +1,6 @@
11MIT License
22
3−Copyright (c) 2021 Aleksey Uymanov
3+Copyright (c) 2021 Typeable
44
55Permission is hereby granted, free of charge, to any person obtaining a copy
66of this software and associated documentation files (the "Software"), to deal
README.md+326−4
@@ -1,8 +1,330 @@
1−# openapi-diff
1+# compaREST
22
3−[![Hackage](https://img.shields.io/hackage/v/openapi-diff.svg?logo=haskell)](https://hackage.haskell.org/package/openapi-diff)
4−[![Stackage Lts](http://stackage.org/package/openapi-diff/badge/lts)](http://stackage.org/lts/package/openapi-diff)
5−[![Stackage Nightly](http://stackage.org/package/openapi-diff/badge/nightly)](http://stackage.org/nightly/package/openapi-diff)
3+[![Hackage](https://img.shields.io/hackage/v/compaREST.svg?logo=haskell)](https://hackage.haskell.org/package/compaREST)
64[![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
75
86Compatibility checker for OpenAPI
7+
8+## Using compaREST in Github Actions
9+
10+Add the following step to your Github Actions workflow:
11+
12+```yaml
13+- uses: typeable/comparest
14+ if: ${{ github.event_name == 'pull_request' }}
15+ with:
16+ old: old-openapi.yaml
17+ new: new-openapi.yaml
18+```
19+
20+The `new` and `old` values should be paths to your OpenAPI specifications you want to compare.
21+
22+You will get something like this in your pull requests:
23+
24+![](docs/img/github-action-report.png)
25+
26+For more detail please see our [integration guide](docs/Integration_guide.md).
27+
28+## An example
29+
30+### Your situation
31+
32+You are developing a very important server with a REST API. You have clients who use your API that you do not control. Say, you are also developing a mobile app that uses your API and you can't force someone to update to the latest version. (Or you prefer not to for UX reasons.)
33+
34+You have recently released version 1.0 and things are going great: user are downloading your app, servers are processing requests.
35+
36+You describe your API in a file `api-1.0.0.yaml`:
37+
38+```yaml
39+openapi: "3.0.0"
40+info:
41+ version: 1.0.0
42+ title: Swagger Petstore
43+ license:
44+ name: MIT
45+servers:
46+ - url: https://example.com
47+paths:
48+ /pets:
49+ get:
50+ parameters:
51+ - name: limit
52+ in: query
53+ required: false
54+ schema:
55+ type: integer
56+ maximum: 20
57+ responses:
58+ "200":
59+ description: ""
60+ headers:
61+ x-next:
62+ schema:
63+ type: string
64+ content:
65+ application/json:
66+ schema:
67+ $ref: "#/components/schemas/Pets"
68+ post:
69+ requestBody:
70+ content:
71+ application/json:
72+ schema:
73+ $ref: "#/components/schemas/Pet"
74+ responses:
75+ "201":
76+ description: ""
77+components:
78+ schemas:
79+ Pet:
80+ type: object
81+ required:
82+ - id
83+ - name
84+ properties:
85+ id:
86+ type: integer
87+ name:
88+ type: string
89+ minLength: 3
90+ maxLength: 10
91+ Pets:
92+ type: array
93+ items:
94+ $ref: "#/components/schemas/Pet"
95+```
96+
97+### Evolving your product
98+
99+Enthused over your initial success you hurry to release a new and improved version of your API and mobile app.
100+
101+After a round of very intense programming you take a look at your new `api-1.1.0.yaml`:
102+
103+```yaml
104+openapi: "3.0.0"
105+info:
106+ version: 1.1.0
107+ title: Swagger Petstore
108+ license:
109+ name: MIT
110+servers:
111+ - url: https://example.com
112+paths:
113+ /pets:
114+ get:
115+ parameters:
116+ - name: limit
117+ in: query
118+ required: false
119+ schema:
120+ type: integer
121+ maximum: 30
122+ responses:
123+ "200":
124+ description: ""
125+ headers:
126+ x-next:
127+ schema:
128+ type: string
129+ content:
130+ application/json:
131+ schema:
132+ $ref: "#/components/schemas/Pets"
133+ post:
134+ requestBody:
135+ content:
136+ application/json:
137+ schema:
138+ $ref: "#/components/schemas/Pet"
139+ responses:
140+ "201":
141+ description: ""
142+components:
143+ schemas:
144+ Pet:
145+ type: object
146+ required:
147+ - id
148+ - name
149+ properties:
150+ id:
151+ type: integer
152+ name:
153+ type: string
154+ minLength: 1
155+ maxLength: 15
156+ weight:
157+ type: integer
158+ Pets:
159+ type: array
160+ items:
161+ $ref: "#/components/schemas/Pet"
162+```
163+
164+Looking at the very large and complex API description, you grow more and more concerned that your old mobile app might stop working when you update the server. But the spec is too large and too complex to reasonably assess this manually.
165+
166+### Assessing compatibility automatically
167+
168+Luckily, you have access to compaREST which can programmatically analyze your APIs and determine what, if anything, breaks compatibility and what doesn't.
169+
170+You can call it, passing the API your client will be aware of, and the API your server will serve like so:
171+
172+```bash
173+docker run --rm -v $(pwd):/data:rw typeable/comparest --client /data/api-1.0.0.yaml --server /data/api-1.1.0.yaml --output /data/report.md
174+```
175+
176+Running this command will output a file `report.md`, containing the compatibility report between the two APIs:
177+
178+> # Summary
179+>
180+> | [❌ Breaking changes](#breaking-changes) | [⚠️ Non-breaking changes](#non-breaking-changes) |
181+> |------------------------------------------|--------------------------------------------------|
182+> | 5 | 6 |
183+>
184+> # <span id="breaking-changes"></span>❌ Breaking changes
185+>
186+> ## **GET** /pets
187+>
188+> ### ⬅️☁️ JSON Response – 200
189+>
190+> #### `$[*].name(String)`
191+>
192+> 1. Maximum length of the string changed from 10 to 15.
193+>
194+> 2. Minimum length of the string changed from 3 to 1.
195+>
196+> ## **POST** /pets
197+>
198+> ### ➡️☁️ JSON Request
199+>
200+> #### `$.weight`
201+>
202+> 1. Values are now limited to the following types:
203+>
204+> - Number
205+>
206+> 2. The property was previously implicitly described by the catch-all
207+> "additional properties" case. It is now explicitly defined.
208+>
209+> #### `$.weight(Number)`
210+>
211+> Value is now a multiple of 1.0.
212+>
213+> # <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
214+>
215+> ## **GET** /pets
216+>
217+> ### Parameter limit
218+>
219+> #### JSON Schema
220+>
221+> ##### `$(Number)`
222+>
223+> Upper bound changed from 20.0 inclusive to 30.0 inclusive.
224+>
225+> ### ⬅️☁️ JSON Response – 200
226+>
227+> #### `$[*].weight`
228+>
229+> 1. Values are now limited to the following types:
230+>
231+> - Number
232+>
233+> 2. The property was previously implicitly described by the catch-all
234+> "additional properties" case. It is now explicitly defined.
235+>
236+> #### `$[*].weight(Number)`
237+>
238+> Value is now a multiple of 1.0.
239+>
240+> ## **POST** /pets
241+>
242+> ### ➡️☁️ JSON Request
243+>
244+> #### `$.name(String)`
245+>
246+> 1. Maximum length of the string changed from 10 to 15.
247+>
248+> 2. Minimum length of the string changed from 3 to 1.
249+
250+You now know exactly in what situations and in what way your 1.0 version of the app will break if you deploy your 1.1 version of the server.
251+
252+### Additional formats
253+
254+You can also produce a self-contained HTML report that you can open in your browser by simply omitting the file extension of the output file:
255+
256+```bash
257+docker run --rm -v $(pwd):/data:rw typeable/comparest --client /data/api-1.0.0.yaml --server /data/api-1.1.0.yaml --output /data/report
258+```
259+
260+## CLI docs
261+
262+For more detail please see our [user guide](docs/User_guide.md).
263+
264+```
265+Usage: comparest (-c|--client ARG) (-s|--server ARG)
266+ [--silent | --only-breaking | --all] [-o|--output ARG]
267+ [--folding-block-quotes-style | --header-style]
268+ [--signal-exit-code]
269+ A tool to check compatibility between two OpenAPI specifications.
270+
271+ Usage examples
272+
273+ Compare files old.yaml with new.yaml and output the resulting report to
274+ stdout:
275+
276+ comparest -c old.yaml -s new.yaml
277+
278+ Only output breaking changes and write a styled HTML report to file
279+ report.html:
280+
281+ comparest -c old.yaml -s new.yaml --only-breaking -o report
282+
283+ Don't output anything, only fail if there are breaking changes:
284+
285+ comparest -c old.json -s new.json --silent
286+
287+ Write full report suitable for embedding into a GitHub comment to
288+ report.html:
289+
290+ comparest -c old.json -s new.json --folding-block-quotes-style -o report.html
291+
292+Available options:
293+ -h,--help Show this help text
294+ -c,--client ARG A path to the file containing the specification that
295+ will be used for the client of the API. Can be either
296+ a YAML or JSON file.
297+ -s,--server ARG A path to the file containing the specification that
298+ will be used for the server of the API. Can be either
299+ a YAML or JSON file.
300+ --silent Silence all output. Only makes sense in combination
301+ with --signal-exit-code.
302+ --only-breaking Only report breaking changes in the output.
303+ --all Report both incompatible and compatible changes.
304+ Compatible changes will not trigger a failure exit
305+ code.
306+ -o,--output ARG The file path where the output should be written. If
307+ the option is omitted the result will be written to
308+ stdout.
309+
310+ The file extension is used to determine the type of
311+ the output file.
312+
313+ Supports many formats such as markdown, html, rtf,
314+ doc, txt, rst, and many more.
315+
316+ Leave out the extension to produce a self-contained
317+ HTML report with styling.
318+ --folding-block-quotes-style
319+ The report tree is structured using summary/detail
320+ HTML elements and indented using block quotes. This
321+ style renders well on GitHub.Intended for HTML output
322+ format. Markdown has rendering bugs on GitHub.
323+ --header-style The report tree is structured using increasing levels
324+ of headers.
325+ --signal-exit-code Signal API compatibility with the exit code.
326+
327+ Exit with 0 if there are no breaking changes.
328+ Exit with 1 if there are breaking changes.
329+ Exit with 2 if could not determine compatibility.
330+```
action.yamlnew file+48
@@ -0,0 +1,48 @@
1+name: compaREST
2+author: Typeable
3+description: API reliability checker
4+inputs:
5+ GITHUB_TOKEN:
6+ description: "The GitHub access token (e.g. secrets.GITHUB_TOKEN) used to create or update the comment. This defaults to {{ github.token }}."
7+ default: "${{ github.token }}"
8+ required: false
9+ repo:
10+ description: The owner of the repo in which to post the results.
11+ default: "${{ github.repository }}"
12+ required: false
13+ project_name:
14+ description: The name of the project to which the API pertains. Used to name the check. Useful when you have multiple APIs in the same repo.
15+ required: false
16+ default: ""
17+ footer:
18+ description: A footer that can be appended to the check body.
19+ required: false
20+ default: ""
21+ old:
22+ description: The path to the old (client) specification of the API.
23+ required: true
24+ new:
25+ description: The path to new (server) specification of the API.
26+ required: true
27+ sha:
28+ description: The sha of the commit to post the check for.
29+ required: false
30+ default: "${{ github.event.pull_request.head.sha }}"
31+runs:
32+ using: "docker"
33+ image: "docker://typeable/comparest-github-action:0.1.0.1"
34+ env:
35+ GITHUB_TOKEN: "${{ inputs.GITHUB_TOKEN }}"
36+ REPO: "${{ inputs.repo }}"
37+ PROJECT_NAME: "${{ inputs.project_name }}"
38+ FOOTER: "${{ inputs.footer }}"
39+ ROOT: "/github/workspace"
40+ OLD: "${{ inputs.old }}"
41+ NEW: "${{ inputs.new }}"
42+ SHA: "${{ inputs.sha }}"
43+ pre-entrypoint: "/bin/pre"
44+ entrypoint: "/bin/run"
45+
46+branding:
47+ icon: crosshair
48+ color: blue
app/Data/OpenApi/Compare/Options.hsnew file+135
@@ -0,0 +1,135 @@
1+module Data.OpenApi.Compare.Options
2+ ( Options (..),
3+ OutputMode (..),
4+ parseOptions,
5+ )
6+where
7+
8+import Data.OpenApi.Compare.Report
9+import GHC.Generics (Generic)
10+import Options.Applicative
11+import Options.Applicative.Help hiding (fullDesc)
12+import Text.PrettyPrint.ANSI.Leijen ((<$$>),string)
13+
14+parseOptions :: IO Options
15+parseOptions = customExecParser (prefs $ showHelpOnError) optionsParserInfo
16+
17+data Options = Options
18+ { clientFile :: FilePath
19+ , serverFile :: FilePath
20+ , -- | 'Nothing' means "don't produce any output"
21+ mode :: Maybe ReportMode
22+ , outputMode :: OutputMode
23+ , reportTreeStyle :: ReportTreeStyle
24+ , signalExitCode :: Bool
25+ }
26+ deriving stock (Generic)
27+
28+data OutputMode = StdoutMode | FileMode FilePath
29+
30+optionsParserInfo :: ParserInfo Options
31+optionsParserInfo =
32+ info
33+ (helper <*> optionsParser)
34+ ( fullDesc
35+ <> header "CompaREST"
36+ <> progDescDoc
37+ ( Just $
38+ par "A tool to check compatibility between two OpenAPI specifications."
39+ <$$> hardline <> par "Usage examples" <> hardline
40+ <$$> indent
41+ 4
42+ ( par "Compare files old.yaml with new.yaml and output the resulting report to stdout:"
43+ <$$> hardline <> indent 4 "comparest -c old.yaml -s new.yaml"
44+ <$$> hardline <> par "Only output breaking changes and write a styled HTML report to file report.html:"
45+ <$$> hardline <> indent 4 "comparest -c old.yaml -s new.yaml --only-breaking -o report"
46+ <$$> hardline <> par "Don't output anything, only fail if there are breaking changes:"
47+ <$$> hardline <> indent 4 "comparest -c old.json -s new.json --silent"
48+ <$$> hardline <> par "Write full report suitable for embedding into a GitHub comment to report.html:"
49+ <$$> hardline <> indent 4 "comparest -c old.json -s new.json --folding-block-quotes-style -o report.html"
50+ )
51+ )
52+ )
53+
54+optionsParser :: Parser Options
55+optionsParser =
56+ Options
57+ <$> strOption
58+ ( short 'c'
59+ <> long "client"
60+ <> help
61+ "A path to the file containing the specification that will be \
62+ \used for the client of the API. Can be either a YAML or JSON file."
63+ )
64+ <*> strOption
65+ ( short 's'
66+ <> long "server"
67+ <> help
68+ "A path to the file containing the specification that will be \
69+ \used for the server of the API. Can be either a YAML or JSON file."
70+ )
71+ <*> ( flag'
72+ Nothing
73+ ( long "silent"
74+ <> help "Silence all output. Only makes sense in combination with --signal-exit-code."
75+ )
76+ <|> flag'
77+ (Just OnlyErrors)
78+ ( long "only-breaking"
79+ <> help "Only report breaking changes in the output."
80+ )
81+ <|> flag'
82+ (Just All)
83+ ( long "all"
84+ <> help
85+ "Report both incompatible and compatible changes. \
86+ \Compatible changes will not trigger a failure exit code."
87+ )
88+ <|> pure (Just All)
89+ )
90+ <*> ( ( FileMode
91+ <$> strOption
92+ ( short 'o' <> long "output"
93+ <> helpDoc
94+ ( Just $
95+ par "The file path where the output should be written. If the option is omitted the result will be written to stdout."
96+ <$$> hardline <> par "The file extension is used to determine the type of the output file."
97+ <$$> hardline <> par "Supports many formats such as markdown, html, rtf, doc, txt, rst, and many more."
98+ <$$> hardline <> par "Leave out the extension to produce a self-contained HTML report with styling."
99+ )
100+ )
101+ )
102+ <|> pure StdoutMode
103+ )
104+ <*> ( flag'
105+ FoldingBlockquotesTreeStyle
106+ ( long "folding-block-quotes-style"
107+ <> help
108+ "The report tree is structured using \
109+ \summary/detail HTML elements and indented using \
110+ \block quotes. This style renders well on GitHub.\
111+ \Intended for HTML output format. Markdown has rendering \
112+ \bugs on GitHub."
113+ )
114+ <|> flag'
115+ HeadersTreeStyle
116+ ( long "header-style"
117+ <> help
118+ "The report tree is structured using \
119+ \increasing levels of headers."
120+ )
121+ <|> pure HeadersTreeStyle
122+ )
123+ <*> switch
124+ ( long "signal-exit-code"
125+ <> helpDoc
126+ ( Just $
127+ par "Signal API compatibility with the exit code."
128+ <$$> hardline <> par "Exit with 0 if there are no breaking changes."
129+ <$$> par "Exit with 1 if there are breaking changes."
130+ <$$> par "Exit with 2 if could not determine compatibility."
131+ )
132+ )
133+
134+par :: String -> Doc
135+par = foldr1 (</>) . fmap string . words
app/FormatHeuristic.hs+80−54
@@ -2,68 +2,94 @@
22-- Originally based on:
33-- https://github.com/jgm/pandoc/blob/master/src/Text/Pandoc/App/FormatHeuristics.hs
44module FormatHeuristic
5− ( formatFromFilePath
5+ ( formatFromFilePath,
66 )
77where
88
9+import Data.ByteString.Lazy (ByteString)
910import Data.Char (toLower)
11+import Data.Functor
12+import qualified Data.Map as M
13+import qualified Data.OpenApi.Compare.Report.Html.Template as Html
14+import Data.Text (Text)
15+import qualified Data.Text.Lazy as TL
16+import qualified Data.Text.Lazy.Encoding as TL
1017import System.FilePath (takeExtension)
18+import Text.DocTemplates.Internal
1119import Text.Pandoc
1220
13−formatFromFilePath :: PandocMonad m => FilePath -> Maybe (Writer m)
21+formatFromFilePath :: forall m. PandocMonad m => FilePath -> Maybe (Pandoc -> m ByteString, FilePath)
1422formatFromFilePath x =
1523 case takeExtension (map toLower x) of
16− ".adoc" -> f "asciidoc"
17− ".asciidoc" -> f "asciidoc"
18− ".context" -> f "context"
19− ".ctx" -> f "context"
20− ".db" -> f "docbook"
21− ".doc" -> f "doc" -- so we get an "unknown reader" error
22− ".docx" -> f "docx"
23− ".dokuwiki" -> f "dokuwiki"
24− ".epub" -> f "epub"
25− ".fb2" -> f "fb2"
26− ".htm" -> f "html"
27− ".html" -> f "html"
28− ".icml" -> f "icml"
29− ".json" -> f "json"
30− ".latex" -> f "latex"
31− ".lhs" -> f "markdown+lhs"
32− ".ltx" -> f "latex"
33− ".markdown" -> f "markdown"
34− ".mkdn" -> f "markdown"
35− ".mkd" -> f "markdown"
36− ".mdwn" -> f "markdown"
37− ".mdown" -> f "markdown"
38− ".Rmd" -> f "markdown"
39− ".md" -> f "markdown"
40− ".ms" -> f "ms"
41− ".muse" -> f "muse"
42− ".native" -> f "native"
43− ".odt" -> f "odt"
44− ".opml" -> f "opml"
45− ".org" -> f "org"
46− ".pdf" -> f "pdf" -- so we get an "unknown reader" error
47− ".pptx" -> f "pptx"
48− ".roff" -> f "ms"
49− ".rst" -> f "rst"
50− ".rtf" -> f "rtf"
51− ".s5" -> f "s5"
52− ".t2t" -> f "t2t"
53− ".tei" -> f "tei"
54− ".tei.xml" -> f "tei"
55− ".tex" -> f "latex"
56− ".texi" -> f "texinfo"
57− ".texinfo" -> f "texinfo"
58− ".text" -> f "markdown"
59− ".textile" -> f "textile"
60− ".txt" -> f "markdown"
61− ".wiki" -> f "mediawiki"
62− ".xhtml" -> f "html"
63− ".ipynb" -> f "ipynb"
64− ".csv" -> f "csv"
65− ".bib" -> f "biblatex"
66− ['.', y] | y `elem` ['1' .. '9'] -> f "man"
24+ ".adoc" -> fWithDefaultFile "asciidoc" def
25+ ".asciidoc" -> fWithDefaultFile "asciidoc" def
26+ ".context" -> fWithDefaultFile "context" def
27+ ".ctx" -> fWithDefaultFile "context" def
28+ ".db" -> fWithDefaultFile "docbook" def
29+ ".doc" -> fWithDefaultFile "doc" def -- so we get an "unknown reader" error
30+ ".docx" -> fWithDefaultFile "docx" def
31+ ".dokuwiki" -> fWithDefaultFile "dokuwiki" def
32+ ".epub" -> fWithDefaultFile "epub" def
33+ ".fb2" -> fWithDefaultFile "fb2" def
34+ ".htm" -> fWithDefaultFile "html" def
35+ ".html" -> fWithDefaultFile "html" def
36+ ".icml" -> fWithDefaultFile "icml" def
37+ ".json" -> fWithDefaultFile "json" def
38+ ".latex" -> fWithDefaultFile "latex" def
39+ ".lhs" -> fWithDefaultFile "markdown+lhs" def
40+ ".ltx" -> fWithDefaultFile "latex" def
41+ ".markdown" -> markdown
42+ ".mkdn" -> markdown
43+ ".mkd" -> markdown
44+ ".mdwn" -> markdown
45+ ".mdown" -> markdown
46+ ".Rmd" -> markdown
47+ ".md" -> markdown
48+ ".ms" -> fWithDefaultFile "ms" def
49+ ".muse" -> fWithDefaultFile "muse" def
50+ ".native" -> fWithDefaultFile "native" def
51+ ".odt" -> fWithDefaultFile "odt" def
52+ ".opml" -> fWithDefaultFile "opml" def
53+ ".org" -> fWithDefaultFile "org" def
54+ -- so we get an "unknown reader" error
55+ ".pdf" -> fWithDefaultFile "pdf" def
56+ ".pptx" -> fWithDefaultFile "pptx" def
57+ ".roff" -> fWithDefaultFile "ms" def
58+ ".rst" -> fWithDefaultFile "rst" def
59+ ".rtf" -> fWithDefaultFile "rtf" def
60+ ".s5" -> fWithDefaultFile "s5" def
61+ ".t2t" -> fWithDefaultFile "t2t" def
62+ ".tei" -> fWithDefaultFile "tei" def
63+ ".tei.xml" -> fWithDefaultFile "tei" def
64+ ".tex" -> fWithDefaultFile "latex" def
65+ ".texi" -> fWithDefaultFile "texinfo" def
66+ ".texinfo" -> fWithDefaultFile "texinfo" def
67+ ".text" -> markdown
68+ ".textile" -> fWithDefaultFile "textile" def
69+ ".txt" -> markdown
70+ ".wiki" -> fWithDefaultFile "mediawiki" def
71+ ".xhtml" -> fWithDefaultFile "html" def
72+ ".ipynb" -> fWithDefaultFile "ipynb" def
73+ ".csv" -> fWithDefaultFile "csv" def
74+ ".bib" -> fWithDefaultFile "biblatex" def
75+ ['.', y] | y `elem` ['1' .. '9'] -> fWithDefaultFile "man" def
76+ "" ->
77+ (,x <> ".html")
78+ <$> f
79+ "html"
80+ def
81+ { writerTemplate = Just Html.template
82+ , -- Not actually used. Needed to silence warning.
83+ writerVariables = Context $ M.fromList [("pagetitle", toVal ("CompaREST" :: Text))]
84+ }
6785 _ -> Nothing
6886 where
69− f k = lookup k writers
87+ markdown :: Maybe (Pandoc -> m ByteString, FilePath)
88+ markdown = fWithDefaultFile "markdown" markdownOpt
89+
90+ markdownOpt = def {writerExtensions = githubMarkdownExtensions}
91+ fWithDefaultFile k opt = (,x) <$> f k opt
92+ f k opt =
93+ lookup k writers <&> \case
94+ TextWriter g -> fmap (TL.encodeUtf8 . TL.fromStrict) . g opt
95+ ByteStringWriter g -> g opt
app/Main.hs+29−22
@@ -2,26 +2,24 @@ module Main (main) where
22
33import Control.Monad
44import Control.Monad.Except
5+import Control.Monad.Trans (lift)
56import Data.Aeson
67import qualified Data.ByteString.Lazy as BSL
78import Data.Default
8−import Data.HList
9+import Data.Maybe
10+import Data.OpenApi.Compare.Options
11+import Data.OpenApi.Compare.Run
912import qualified Data.Text.IO as T
1013import qualified Data.Yaml as Yaml
1114import FormatHeuristic
12−import OpenAPI.Checker.Behavior
13−import OpenAPI.Checker.Options
14−import OpenAPI.Checker.Paths
15−import OpenAPI.Checker.PathsPrefixTree
16−import OpenAPI.Checker.Report
17−import OpenAPI.Checker.Subtree
1815import System.Exit
1916import System.IO
20−import Text.Pandoc
17+import Text.Pandoc hiding (report)
18+import Text.Pandoc.Builder
2119
2220main :: IO ()
2321main = do
24− opts <- execParser optionsParserInfo
22+ opts <- parseOptions
2523 let parseSchema path =
2624 eitherDecodeFileStrict path >>= \case
2725 Left jsonErr -> do
@@ -33,22 +31,31 @@ main = do
3331 fail "Exiting"
3432 Right s -> pure s
3533 Right s -> pure s
36− a <- traced (step ClientSchema) <$> parseSchema (clientFile opts)
37− b <- traced (step ServerSchema) <$> parseSchema (serverFile opts)
38− let result = runCompatFormula $ checkCompatibility HNil Root (ProdCons a b)
39− runPandocIO :: PandocIO a -> ExceptT Errors IO a
34+ a <- parseSchema (clientFile opts)
35+ b <- parseSchema (serverFile opts)
36+ let runPandocIO :: PandocIO a -> ExceptT Errors IO a
4037 runPandocIO x = lift (runIO x) >>= either (throwError . DocumentError) pure
41− output :: Either (PathsPrefixTree Behave AnIssue 'APILevel) () -> ExceptT Errors IO ()
42− output = case outputMode opts of
43− StdoutMode -> lift . T.putStrLn <=< runPandocIO . writeMarkdown def . generateReport
38+ options = def {writerExtensions = githubMarkdownExtensions}
39+ write :: Pandoc -> ExceptT Errors IO ()
40+ write = case outputMode opts of
41+ StdoutMode -> lift . T.putStrLn <=< runPandocIO . writeMarkdown options
4442 FileMode f -> case formatFromFilePath f of
4543 Nothing -> \_ -> throwError UnknownOutputFormat
46− Just (TextWriter writer) -> lift . T.writeFile f <=< runPandocIO . writer def . generateReport
47− Just (ByteStringWriter writer) -> lift . BSL.writeFile f <=< runPandocIO . writer def . generateReport
48− either handler pure <=< runExceptT $ output result
49− case result of
50− Right () -> exitSuccess
51− Left _ -> exitWith $ ExitFailure 1
44+ Just (writer, f') -> lift . BSL.writeFile f' <=< runPandocIO . writer
45+ reportConfig =
46+ ReportConfig
47+ { treeStyle = reportTreeStyle opts
48+ , reportMode = fromMaybe All $ mode opts
49+ }
50+ (report, status) = runReport reportConfig (a, b)
51+ case mode opts of
52+ Just _ -> either handler pure <=< runExceptT $ write $ doc report
53+ Nothing -> pure ()
54+ when (signalExitCode opts) $
55+ case status of
56+ NoBreakingChanges -> exitSuccess
57+ BreakingChanges -> exitWith $ ExitFailure 1
58+ OnlyUnsupportedChanges -> exitWith $ ExitFailure 2
5259
5360data Errors
5461 = DocumentError PandocError
benchmarks/README.mdnew file+27
@@ -0,0 +1,27 @@
1+# OpenApi comparison benchmarks
2+
3+This is a nix expression that automatically downloads, builds and runs multiple OpenAPI comparison tools on the same set of inputs to compare how well they behave.
4+
5+To run the benchmarks run the following command in this directory:
6+
7+```bash
8+nix-build
9+```
10+
11+## The tools
12+
13+| Tool | Output file name |
14+| -------------------------------------------------------------------------- | ------------------------------------------- |
15+| [Typeable CompaREST](https://github.com/typeable/compaREST) | `typeable.md` |
16+| [Atlassian OpenApi Diff](https://bitbucket.org/atlassian/openapi-diff) | `atlassian.json`, `atlassian.error.txt` |
17+| [OpenApi Tools OpenApi Diff](https://github.com/OpenAPITools/openapi-diff) | `openapitools.md`, `openapitools.error.txt` |
18+| [Tufin OpenApi Diff](https://github.com/tufin/oasdiff) | `oasdiff.txt`, `oasdiff.error.txt` |
19+| [Bump](https://bump.sh) | `bump.txt` |
20+
21+## Running with Bump.sh
22+
23+Bump.sh is a closed-source tool that is only available via REST API. To include bump.sh in the benchmark results you have to supply your credentials as arguments:
24+
25+```bash
26+nix-build --argstr bumpToken <TOKEN> --argstr bumpDocumentation <DOCUMENTATION IDENTIFIER>
27+```
benchmarks/atlassian/addDist.patchnew file+10
@@ -0,0 +1,10 @@
1+diff --git a/gulpfile.js b/gulpfile.js
2+index c3161cf..c123cc0 100644
3+--- a/gulpfile.js
4++++ b/gulpfile.js
5+@@ -153,3 +153,5 @@ exports.watch = gulp.series(
6+ exports.watchE2e = function () {
7+ gulp.watch(['build-output/lib/**/*', 'build-output/test/e2e/**/*', 'test/e2e/**/*.json'], gulp.series(e2eTest));
8+ };
9++
10++exports.compileDist = compileDist
benchmarks/atlassian/yarn.locknew file+4918
@@ -0,0 +1,4918 @@
1+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+# yarn lockfile v1
3+
4+
5+"@apidevtools/json-schema-ref-parser@9.0.9", "@apidevtools/json-schema-ref-parser@^9.0.6":
6+ version "9.0.9"
7+ resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#d720f9256e3609621280584f2b47ae165359268b"
8+ integrity sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==
9+ dependencies:
10+ "@jsdevtools/ono" "^7.1.3"
11+ "@types/json-schema" "^7.0.6"
12+ call-me-maybe "^1.0.1"
13+ js-yaml "^4.1.0"
14+
15+"@apidevtools/openapi-schemas@^2.0.4":
16+ version "2.1.0"
17+ resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17"
18+ integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==
19+
20+"@apidevtools/swagger-methods@^3.0.2":
21+ version "3.0.2"
22+ resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267"
23+ integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==
24+
25+"@apidevtools/swagger-parser@10.0.2":
26+ version "10.0.2"
27+ resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.0.2.tgz#f4145afb7c3a3bafe0376f003b5c3bdeae17a952"
28+ integrity sha512-JFxcEyp8RlNHgBCE98nwuTkZT6eNFPc1aosWV6wPcQph72TSEEu1k3baJD4/x1qznU+JiDdz8F5pTwabZh+Dhg==
29+ dependencies:
30+ "@apidevtools/json-schema-ref-parser" "^9.0.6"
31+ "@apidevtools/openapi-schemas" "^2.0.4"
32+ "@apidevtools/swagger-methods" "^3.0.2"
33+ "@jsdevtools/ono" "^7.1.3"
34+ call-me-maybe "^1.0.1"
35+ z-schema "^4.2.3"
36+
37+"@babel/code-frame@^7.0.0":
38+ version "7.14.5"
39+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
40+ integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
41+ dependencies:
42+ "@babel/highlight" "^7.14.5"
43+
44+"@babel/helper-validator-identifier@^7.14.5":
45+ version "7.14.5"
46+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8"
47+ integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==
48+
49+"@babel/highlight@^7.14.5":
50+ version "7.14.5"
51+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
52+ integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
53+ dependencies:
54+ "@babel/helper-validator-identifier" "^7.14.5"
55+ chalk "^2.0.0"
56+ js-tokens "^4.0.0"
57+
58+"@commitlint/cli@^8.3.5":
59+ version "8.3.5"
60+ resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-8.3.5.tgz#6d93a3a8b2437fa978999d3f6a336bcc70be3fd3"
61+ integrity sha512-6+L0vbw55UEdht71pgWOE55SRgb+8OHcEwGDB234VlIBFGK9P2QOBU7MHiYJ5cjdjCQ0rReNrGjOHmJ99jwf0w==
62+ dependencies:
63+ "@commitlint/format" "^8.3.4"
64+ "@commitlint/lint" "^8.3.5"
65+ "@commitlint/load" "^8.3.5"
66+ "@commitlint/read" "^8.3.4"
67+ babel-polyfill "6.26.0"
68+ chalk "2.4.2"
69+ get-stdin "7.0.0"
70+ lodash "4.17.15"
71+ meow "5.0.0"
72+ resolve-from "5.0.0"
73+ resolve-global "1.0.0"
74+
75+"@commitlint/config-conventional@^8.3.4":
76+ version "8.3.4"
77+ resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-8.3.4.tgz#fed13b3711690663b176c1f6b39c205a565618d2"
78+ integrity sha512-w0Yc5+aVAjZgjYqx29igBOnVCj8O22gy3Vo6Fyp7PwoS7+AYS1x3sN7IBq6i7Ae15Mv5P+rEx1pkxXo5zOMe4g==
79+ dependencies:
80+ conventional-changelog-conventionalcommits "4.2.1"
81+
82+"@commitlint/ensure@^8.3.4":
83+ version "8.3.4"
84+ resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-8.3.4.tgz#6931677e4ca0fde71686ae3b7a367261647a341d"
85+ integrity sha512-8NW77VxviLhD16O3EUd02lApMFnrHexq10YS4F4NftNoErKbKaJ0YYedktk2boKrtNRf/gQHY/Qf65edPx4ipw==
86+ dependencies:
87+ lodash "4.17.15"
88+
89+"@commitlint/execute-rule@^8.3.4":
90+ version "8.3.4"
91+ resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-8.3.4.tgz#1b63f0713b197889d90b76f9eea1abc010d256b1"
92+ integrity sha512-f4HigYjeIBn9f7OuNv5zh2y5vWaAhNFrfeul8CRJDy82l3Y+09lxOTGxfF3uMXKrZq4LmuK6qvvRCZ8mUrVvzQ==
93+
94+"@commitlint/format@^8.3.4":
95+ version "8.3.4"
96+ resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-8.3.4.tgz#7cd1f0ba5a3289c8d14d7dac29ee1fc1597fe1d9"
97+ integrity sha512-809wlQ/ND6CLZON+w2Rb3YM2TLNDfU2xyyqpZeqzf2reJNpySMSUAeaO/fNDJSOKIsOsR3bI01rGu6hv28k+Nw==
98+ dependencies:
99+ chalk "^2.0.1"
100+
101+"@commitlint/is-ignored@^8.3.5":
102+ version "8.3.5"
103+ resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-8.3.5.tgz#e6f59496e1b1ce58020d519cd578ad0f43169199"
104+ integrity sha512-Zo+8a6gJLFDTqyNRx53wQi/XTiz8mncvmWf/4oRG+6WRcBfjSSHY7KPVj5Y6UaLy2EgZ0WQ2Tt6RdTDeQiQplA==
105+ dependencies:
106+ semver "6.3.0"
107+
108+"@commitlint/lint@^8.3.5":
109+ version "8.3.5"
110+ resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-8.3.5.tgz#627e75adb1cc803cc723e33cc2ba4aa27cbb9f0c"
111+ integrity sha512-02AkI0a6PU6rzqUvuDkSi6rDQ2hUgkq9GpmdJqfai5bDbxx2939mK4ZO+7apbIh4H6Pae7EpYi7ffxuJgm+3hQ==
112+ dependencies:
113+ "@commitlint/is-ignored" "^8.3.5"
114+ "@commitlint/parse" "^8.3.4"
115+ "@commitlint/rules" "^8.3.4"
116+ babel-runtime "^6.23.0"
117+ lodash "4.17.15"
118+
119+"@commitlint/load@^8.3.5":
120+ version "8.3.5"
121+ resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-8.3.5.tgz#3f059225ede92166ba94cf4c48e3d67c8b08b18a"
122+ integrity sha512-poF7R1CtQvIXRmVIe63FjSQmN9KDqjRtU5A6hxqXBga87yB2VUJzic85TV6PcQc+wStk52cjrMI+g0zFx+Zxrw==
123+ dependencies:
124+ "@commitlint/execute-rule" "^8.3.4"
125+ "@commitlint/resolve-extends" "^8.3.5"
126+ babel-runtime "^6.23.0"
127+ chalk "2.4.2"
128+ cosmiconfig "^5.2.0"
129+ lodash "4.17.15"
130+ resolve-from "^5.0.0"
131+
132+"@commitlint/message@^8.3.4":
133+ version "8.3.4"
134+ resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-8.3.4.tgz#b4e50d14aa6e15a5ad0767b952a7953f3681d768"
135+ integrity sha512-nEj5tknoOKXqBsaQtCtgPcsAaf5VCg3+fWhss4Vmtq40633xLq0irkdDdMEsYIx8rGR0XPBTukqzln9kAWCkcA==
136+
137+"@commitlint/parse@^8.3.4":
138+ version "8.3.4"
139+ resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-8.3.4.tgz#d741f8b9104b35d0f4c10938165b20cbf167f81e"
140+ integrity sha512-b3uQvpUQWC20EBfKSfMRnyx5Wc4Cn778bVeVOFErF/cXQK725L1bYFvPnEjQO/GT8yGVzq2wtLaoEqjm1NJ/Bw==
141+ dependencies:
142+ conventional-changelog-angular "^1.3.3"
143+ conventional-commits-parser "^3.0.0"
144+ lodash "^4.17.11"
145+
146+"@commitlint/read@^8.3.4":
147+ version "8.3.4"
148+ resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-8.3.4.tgz#81a34283d8cd7b2acdf57829a91761e9c7791455"
149+ integrity sha512-FKv1kHPrvcAG5j+OSbd41IWexsbLhfIXpxVC/YwQZO+FR0EHmygxQNYs66r+GnhD1EfYJYM4WQIqd5bJRx6OIw==
150+ dependencies:
151+ "@commitlint/top-level" "^8.3.4"
152+ "@marionebl/sander" "^0.6.0"
153+ babel-runtime "^6.23.0"
154+ git-raw-commits "^2.0.0"
155+
156+"@commitlint/resolve-extends@^8.3.5":
157+ version "8.3.5"
158+ resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-8.3.5.tgz#8fff800f292ac217ae30b1862f5f9a84b278310a"
159+ integrity sha512-nHhFAK29qiXNe6oH6uG5wqBnCR+BQnxlBW/q5fjtxIaQALgfoNLHwLS9exzbIRFqwJckpR6yMCfgMbmbAOtklQ==
160+ dependencies:
161+ import-fresh "^3.0.0"
162+ lodash "4.17.15"
163+ resolve-from "^5.0.0"
164+ resolve-global "^1.0.0"
165+
166+"@commitlint/rules@^8.3.4":
167+ version "8.3.4"
168+ resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-8.3.4.tgz#41da7e16c6b89af268fe81c87a158c1fd2ac82b1"
169+ integrity sha512-xuC9dlqD5xgAoDFgnbs578cJySvwOSkMLQyZADb1xD5n7BNcUJfP8WjT9W1Aw8K3Wf8+Ym/ysr9FZHXInLeaRg==
170+ dependencies:
171+ "@commitlint/ensure" "^8.3.4"
172+ "@commitlint/message" "^8.3.4"
173+ "@commitlint/to-lines" "^8.3.4"
174+ babel-runtime "^6.23.0"
175+
176+"@commitlint/to-lines@^8.3.4":
177+ version "8.3.4"
178+ resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-8.3.4.tgz#ce24963b6d86dbe51d88d5e3028ab28f38562e2e"
179+ integrity sha512-5AvcdwRsMIVq0lrzXTwpbbG5fKRTWcHkhn/hCXJJ9pm1JidsnidS1y0RGkb3O50TEHGewhXwNoavxW9VToscUA==
180+
181+"@commitlint/top-level@^8.3.4":
182+ version "8.3.4"
183+ resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-8.3.4.tgz#803fc6e8f5be5efa5f3551761acfca961f1d8685"
184+ integrity sha512-nOaeLBbAqSZNpKgEtO6NAxmui1G8ZvLG+0wb4rvv6mWhPDzK1GNZkCd8FUZPahCoJ1iHDoatw7F8BbJLg4nDjg==
185+ dependencies:
186+ find-up "^4.0.0"
187+
188+"@hutson/parse-repository-url@^3.0.0":
189+ version "3.0.2"
190+ resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340"
191+ integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==
192+
193+"@jsdevtools/ono@^7.1.3":
194+ version "7.1.3"
195+ resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796"
196+ integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==
197+
198+"@marionebl/sander@^0.6.0":
199+ version "0.6.1"
200+ resolved "https://registry.yarnpkg.com/@marionebl/sander/-/sander-0.6.1.tgz#1958965874f24bc51be48875feb50d642fc41f7b"
201+ integrity sha1-GViWWHTyS8Ub5Ih1/rUNZC/EH3s=
202+ dependencies:
203+ graceful-fs "^4.1.3"
204+ mkdirp "^0.5.1"
205+ rimraf "^2.5.2"
206+
207+"@nodelib/fs.scandir@2.1.5":
208+ version "2.1.5"
209+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
210+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
211+ dependencies:
212+ "@nodelib/fs.stat" "2.0.5"
213+ run-parallel "^1.1.9"
214+
215+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
216+ version "2.0.5"
217+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
218+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
219+
220+"@nodelib/fs.walk@^1.2.3":
221+ version "1.2.7"
222+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz#94c23db18ee4653e129abd26fb06f870ac9e1ee2"
223+ integrity sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==
224+ dependencies:
225+ "@nodelib/fs.scandir" "2.1.5"
226+ fastq "^1.6.0"
227+
228+"@types/body-parser@*":
229+ version "1.19.0"
230+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
231+ integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==
232+ dependencies:
233+ "@types/connect" "*"
234+ "@types/node" "*"
235+
236+"@types/caseless@*":
237+ version "0.12.2"
238+ resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
239+ integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==
240+
241+"@types/connect@*":
242+ version "3.4.34"
243+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901"
244+ integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==
245+ dependencies:
246+ "@types/node" "*"
247+
248+"@types/express-serve-static-core@^4.17.18":
249+ version "4.17.22"
250+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.22.tgz#e011c55de3f17ddf1161f790042a15c5a218744d"
251+ integrity sha512-WdqmrUsRS4ootGha6tVwk/IVHM1iorU8tGehftQD2NWiPniw/sm7xdJOIlXLwqdInL9wBw/p7oO8vaYEF3NDmA==
252+ dependencies:
253+ "@types/node" "*"
254+ "@types/qs" "*"
255+ "@types/range-parser" "*"
256+
257+"@types/express@^4.17.8":
258+ version "4.17.12"
259+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.12.tgz#4bc1bf3cd0cfe6d3f6f2853648b40db7d54de350"
260+ integrity sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==
261+ dependencies:
262+ "@types/body-parser" "*"
263+ "@types/express-serve-static-core" "^4.17.18"
264+ "@types/qs" "*"
265+ "@types/serve-static" "*"
266+
267+"@types/fancy-log@1.3.0":
268+ version "1.3.0"
269+ resolved "https://registry.yarnpkg.com/@types/fancy-log/-/fancy-log-1.3.0.tgz#a61ab476e5e628cd07a846330df53b85e05c8ce0"
270+ integrity sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw==
271+
272+"@types/jasmine@^3.5.14":
273+ version "3.7.7"
274+ resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.7.7.tgz#56718af036be3c9f86eca560a22e39440b2b0784"
275+ integrity sha512-yZzGe1d1T0y+imXDZ79F030nn8qbmiwpWKCZKvKN0KbTzwXAVYShUxkIxu1ba+vhIdabTGVGCfbtZC0oOam8TQ==
276+
277+"@types/js-yaml@^4.0.0":
278+ version "4.0.1"
279+ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.1.tgz#5544730b65a480b18ace6b6ce914e519cec2d43b"
280+ integrity sha512-xdOvNmXmrZqqPy3kuCQ+fz6wA0xU5pji9cd1nDrflWaAWtYLLGk5ykW0H6yg5TVyehHP1pfmuuSaZkhP+kspVA==
281+
282+"@types/json-schema@^7.0.6":
283+ version "7.0.7"
284+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
285+ integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
286+
287+"@types/lodash@^4.14.162":
288+ version "4.14.170"
289+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6"
290+ integrity sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q==
291+
292+"@types/mime@^1":
293+ version "1.3.2"
294+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
295+ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
296+
297+"@types/minimatch@^3.0.3":
298+ version "3.0.4"
299+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
300+ integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
301+
302+"@types/minimist@^1.2.0":
303+ version "1.2.1"
304+ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256"
305+ integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==
306+
307+"@types/node@*":
308+ version "16.0.0"
309+ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.0.0.tgz#067a6c49dc7a5c2412a505628e26902ae967bf6f"
310+ integrity sha512-TmCW5HoZ2o2/z2EYi109jLqIaPIi9y/lc2LmDCWzuCi35bcaQ+OtUh6nwBiFK7SOu25FAU5+YKdqFZUwtqGSdg==
311+
312+"@types/node@^10.17.39":
313+ version "10.17.60"
314+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b"
315+ integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==
316+
317+"@types/normalize-package-data@^2.4.0":
318+ version "2.4.0"
319+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
320+ integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
321+
322+"@types/qs@*":
323+ version "6.9.6"
324+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.6.tgz#df9c3c8b31a247ec315e6996566be3171df4b3b1"
325+ integrity sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==
326+
327+"@types/range-parser@*":
328+ version "1.2.3"
329+ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
330+ integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
331+
332+"@types/request@^2.48.5":
333+ version "2.48.5"
334+ resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.5.tgz#019b8536b402069f6d11bee1b2c03e7f232937a0"
335+ integrity sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==
336+ dependencies:
337+ "@types/caseless" "*"
338+ "@types/node" "*"
339+ "@types/tough-cookie" "*"
340+ form-data "^2.5.0"
341+
342+"@types/serve-static@*":
343+ version "1.13.9"
344+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.9.tgz#aacf28a85a05ee29a11fb7c3ead935ac56f33e4e"
345+ integrity sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==
346+ dependencies:
347+ "@types/mime" "^1"
348+ "@types/node" "*"
349+
350+"@types/swagger-schema-official@^2.0.21":
351+ version "2.0.22"
352+ resolved "https://registry.yarnpkg.com/@types/swagger-schema-official/-/swagger-schema-official-2.0.22.tgz#f7e06168e6994574dfd86928ac04b196870ab043"
353+ integrity sha512-7yQiX6MWSFSvc/1wW5smJMZTZ4fHOd+hqLr3qr/HONDxHEa2bnYAsOcGBOEqFIjd4yetwMOdEDdeW+udRAQnHA==
354+
355+"@types/tough-cookie@*":
356+ version "4.0.1"
357+ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40"
358+ integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==
359+
360+"@types/verror@^1.10.4":
361+ version "1.10.5"
362+ resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.5.tgz#2a1413aded46e67a1fe2386800e291123ed75eb1"
363+ integrity sha512-9UjMCHK5GPgQRoNbqdLIAvAy0EInuiqbW0PBMtVP6B5B2HQJlvoJHM+KodPZMEjOa5VkSc+5LH7xy+cUzQdmHw==
364+
365+JSONStream@^1.0.4:
366+ version "1.3.5"
367+ resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
368+ integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
369+ dependencies:
370+ jsonparse "^1.2.0"
371+ through ">=2.2.7 <3"
372+
373+accepts@~1.3.7:
374+ version "1.3.7"
375+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
376+ integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
377+ dependencies:
378+ mime-types "~2.1.24"
379+ negotiator "0.6.2"
380+
381+add-stream@^1.0.0:
382+ version "1.0.0"
383+ resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa"
384+ integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=
385+
386+aggregate-error@^3.0.0:
387+ version "3.1.0"
388+ resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
389+ integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
390+ dependencies:
391+ clean-stack "^2.0.0"
392+ indent-string "^4.0.0"
393+
394+ajv@^6.12.3:
395+ version "6.12.6"
396+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
397+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
398+ dependencies:
399+ fast-deep-equal "^3.1.1"
400+ fast-json-stable-stringify "^2.0.0"
401+ json-schema-traverse "^0.4.1"
402+ uri-js "^4.2.2"
403+
404+ansi-colors@^1.0.1:
405+ version "1.1.0"
406+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
407+ integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==
408+ dependencies:
409+ ansi-wrap "^0.1.0"
410+
411+ansi-colors@^3.0.5:
412+ version "3.2.4"
413+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
414+ integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
415+
416+ansi-colors@^4.1.1:
417+ version "4.1.1"
418+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
419+ integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
420+
421+ansi-cyan@^0.1.1:
422+ version "0.1.1"
423+ resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873"
424+ integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=
425+ dependencies:
426+ ansi-wrap "0.1.0"
427+
428+ansi-gray@^0.1.1:
429+ version "0.1.1"
430+ resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251"
431+ integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE=
432+ dependencies:
433+ ansi-wrap "0.1.0"
434+
435+ansi-red@^0.1.1:
436+ version "0.1.1"
437+ resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c"
438+ integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=
439+ dependencies:
440+ ansi-wrap "0.1.0"
441+
442+ansi-regex@^2.0.0:
443+ version "2.1.1"
444+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
445+ integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
446+
447+ansi-styles@^3.2.1:
448+ version "3.2.1"
449+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
450+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
451+ dependencies:
452+ color-convert "^1.9.0"
453+
454+ansi-wrap@0.1.0, ansi-wrap@^0.1.0:
455+ version "0.1.0"
456+ resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
457+ integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768=
458+
459+any-shell-escape@^0.1.1:
460+ version "0.1.1"
461+ resolved "https://registry.yarnpkg.com/any-shell-escape/-/any-shell-escape-0.1.1.tgz#d55ab972244c71a9a5e1ab0879f30bf110806959"
462+ integrity sha1-1Vq5ciRMcaml4asIefML8RCAaVk=
463+
464+anymatch@^2.0.0:
465+ version "2.0.0"
466+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
467+ integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==
468+ dependencies:
469+ micromatch "^3.1.4"
470+ normalize-path "^2.1.1"
471+
472+append-buffer@^1.0.2:
473+ version "1.0.2"
474+ resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1"
475+ integrity sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=
476+ dependencies:
477+ buffer-equal "^1.0.0"
478+
479+archy@^1.0.0:
480+ version "1.0.0"
481+ resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
482+ integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
483+
484+argparse@^1.0.7:
485+ version "1.0.10"
486+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
487+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
488+ dependencies:
489+ sprintf-js "~1.0.2"
490+
491+argparse@^2.0.1:
492+ version "2.0.1"
493+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
494+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
495+
496+arr-diff@^1.0.1:
497+ version "1.1.0"
498+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a"
499+ integrity sha1-aHwydYFjWI/vfeezb6vklesaOZo=
500+ dependencies:
501+ arr-flatten "^1.0.1"
502+ array-slice "^0.2.3"
503+
504+arr-diff@^4.0.0:
505+ version "4.0.0"
506+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
507+ integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
508+
509+arr-filter@^1.1.1:
510+ version "1.1.2"
511+ resolved "https://registry.yarnpkg.com/arr-filter/-/arr-filter-1.1.2.tgz#43fdddd091e8ef11aa4c45d9cdc18e2dff1711ee"
512+ integrity sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=
513+ dependencies:
514+ make-iterator "^1.0.0"
515+
516+arr-flatten@^1.0.1, arr-flatten@^1.1.0:
517+ version "1.1.0"
518+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
519+ integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
520+
521+arr-map@^2.0.0, arr-map@^2.0.2:
522+ version "2.0.2"
523+ resolved "https://registry.yarnpkg.com/arr-map/-/arr-map-2.0.2.tgz#3a77345ffc1cf35e2a91825601f9e58f2e24cac4"
524+ integrity sha1-Onc0X/wc814qkYJWAfnljy4kysQ=
525+ dependencies:
526+ make-iterator "^1.0.0"
527+
528+arr-union@^2.0.1:
529+ version "2.1.0"
530+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d"
531+ integrity sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=
532+
533+arr-union@^3.1.0:
534+ version "3.1.0"
535+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
536+ integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
537+
538+array-differ@^3.0.0:
539+ version "3.0.0"
540+ resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b"
541+ integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==
542+
543+array-each@^1.0.0, array-each@^1.0.1:
544+ version "1.0.1"
545+ resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
546+ integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8=
547+
548+array-find-index@^1.0.1:
549+ version "1.0.2"
550+ resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
551+ integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
552+
553+array-flatten@1.1.1:
554+ version "1.1.1"
555+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
556+ integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
557+
558+array-ify@^1.0.0:
559+ version "1.0.0"
560+ resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece"
561+ integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=
562+
563+array-initial@^1.0.0:
564+ version "1.1.0"
565+ resolved "https://registry.yarnpkg.com/array-initial/-/array-initial-1.1.0.tgz#2fa74b26739371c3947bd7a7adc73be334b3d795"
566+ integrity sha1-L6dLJnOTccOUe9enrcc74zSz15U=
567+ dependencies:
568+ array-slice "^1.0.0"
569+ is-number "^4.0.0"
570+
571+array-last@^1.1.1:
572+ version "1.3.0"
573+ resolved "https://registry.yarnpkg.com/array-last/-/array-last-1.3.0.tgz#7aa77073fec565ddab2493f5f88185f404a9d336"
574+ integrity sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==
575+ dependencies:
576+ is-number "^4.0.0"
577+
578+array-slice@^0.2.3:
579+ version "0.2.3"
580+ resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5"
581+ integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU=
582+
583+array-slice@^1.0.0:
584+ version "1.1.0"
585+ resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4"
586+ integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==
587+
588+array-sort@^1.0.0:
589+ version "1.0.0"
590+ resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a"
591+ integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==
592+ dependencies:
593+ default-compare "^1.0.0"
594+ get-value "^2.0.6"
595+ kind-of "^5.0.2"
596+
597+array-union@^2.1.0:
598+ version "2.1.0"
599+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
600+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
601+
602+array-unique@^0.3.2:
603+ version "0.3.2"
604+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
605+ integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
606+
607+arrify@^1.0.1:
608+ version "1.0.1"
609+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
610+ integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
611+
612+arrify@^2.0.1:
613+ version "2.0.1"
614+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
615+ integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
616+
617+asn1@~0.2.3:
618+ version "0.2.4"
619+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
620+ integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
621+ dependencies:
622+ safer-buffer "~2.1.0"
623+
624+assert-plus@1.0.0, assert-plus@^1.0.0:
625+ version "1.0.0"
626+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
627+ integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
628+
629+assign-symbols@^1.0.0:
630+ version "1.0.0"
631+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
632+ integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
633+
634+async-done@^1.2.0, async-done@^1.2.2:
635+ version "1.3.2"
636+ resolved "https://registry.yarnpkg.com/async-done/-/async-done-1.3.2.tgz#5e15aa729962a4b07414f528a88cdf18e0b290a2"
637+ integrity sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==
638+ dependencies:
639+ end-of-stream "^1.1.0"
640+ once "^1.3.2"
641+ process-nextick-args "^2.0.0"
642+ stream-exhaust "^1.0.1"
643+
644+async-each@^1.0.1:
645+ version "1.0.3"
646+ resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
647+ integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
648+
649+async-settle@^1.0.0:
650+ version "1.0.0"
651+ resolved "https://registry.yarnpkg.com/async-settle/-/async-settle-1.0.0.tgz#1d0a914bb02575bec8a8f3a74e5080f72b2c0c6b"
652+ integrity sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=
653+ dependencies:
654+ async-done "^1.2.2"
655+
656+asynckit@^0.4.0:
657+ version "0.4.0"
658+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
659+ integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
660+
661+atob@^2.1.2:
662+ version "2.1.2"
663+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
664+ integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
665+
666+aws-sign2@~0.7.0:
667+ version "0.7.0"
668+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
669+ integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
670+
671+aws4@^1.8.0:
672+ version "1.11.0"
673+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
674+ integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
675+
676+babel-polyfill@6.26.0:
677+ version "6.26.0"
678+ resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153"
679+ integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=
680+ dependencies:
681+ babel-runtime "^6.26.0"
682+ core-js "^2.5.0"
683+ regenerator-runtime "^0.10.5"
684+
685+babel-runtime@^6.23.0, babel-runtime@^6.26.0:
686+ version "6.26.0"
687+ resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
688+ integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
689+ dependencies:
690+ core-js "^2.4.0"
691+ regenerator-runtime "^0.11.0"
692+
693+bach@^1.0.0:
694+ version "1.2.0"
695+ resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880"
696+ integrity sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=
697+ dependencies:
698+ arr-filter "^1.1.1"
699+ arr-flatten "^1.0.1"
700+ arr-map "^2.0.0"
701+ array-each "^1.0.0"
702+ array-initial "^1.0.0"
703+ array-last "^1.1.1"
704+ async-done "^1.2.2"
705+ async-settle "^1.0.0"
706+ now-and-later "^2.0.0"
707+
708+balanced-match@^1.0.0:
709+ version "1.0.2"
710+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
711+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
712+
713+base@^0.11.1:
714+ version "0.11.2"
715+ resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
716+ integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
717+ dependencies:
718+ cache-base "^1.0.1"
719+ class-utils "^0.3.5"
720+ component-emitter "^1.2.1"
721+ define-property "^1.0.0"
722+ isobject "^3.0.1"
723+ mixin-deep "^1.2.0"
724+ pascalcase "^0.1.1"
725+
726+bcrypt-pbkdf@^1.0.0:
727+ version "1.0.2"
728+ resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
729+ integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
730+ dependencies:
731+ tweetnacl "^0.14.3"
732+
733+binary-extensions@^1.0.0:
734+ version "1.13.1"
735+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
736+ integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
737+
738+bindings@^1.5.0:
739+ version "1.5.0"
740+ resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
741+ integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
742+ dependencies:
743+ file-uri-to-path "1.0.0"
744+
745+body-parser@1.19.0:
746+ version "1.19.0"
747+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
748+ integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
749+ dependencies:
750+ bytes "3.1.0"
751+ content-type "~1.0.4"
752+ debug "2.6.9"
753+ depd "~1.1.2"
754+ http-errors "1.7.2"
755+ iconv-lite "0.4.24"
756+ on-finished "~2.3.0"
757+ qs "6.7.0"
758+ raw-body "2.4.0"
759+ type-is "~1.6.17"
760+
761+brace-expansion@^1.1.7:
762+ version "1.1.11"
763+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
764+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
765+ dependencies:
766+ balanced-match "^1.0.0"
767+ concat-map "0.0.1"
768+
769+braces@^2.3.1, braces@^2.3.2:
770+ version "2.3.2"
771+ resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
772+ integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
773+ dependencies:
774+ arr-flatten "^1.1.0"
775+ array-unique "^0.3.2"
776+ extend-shallow "^2.0.1"
777+ fill-range "^4.0.0"
778+ isobject "^3.0.1"
779+ repeat-element "^1.1.2"
780+ snapdragon "^0.8.1"
781+ snapdragon-node "^2.0.1"
782+ split-string "^3.0.2"
783+ to-regex "^3.0.1"
784+
785+braces@^3.0.1:
786+ version "3.0.2"
787+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
788+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
789+ dependencies:
790+ fill-range "^7.0.1"
791+
792+buffer-equal@^1.0.0:
793+ version "1.0.0"
794+ resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe"
795+ integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74=
796+
797+buffer-from@^1.0.0:
798+ version "1.1.1"
799+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
800+ integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
801+
802+builtin-modules@^1.1.1:
803+ version "1.1.1"
804+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
805+ integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
806+
807+bytes@3.1.0:
808+ version "3.1.0"
809+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
810+ integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
811+
812+cache-base@^1.0.1:
813+ version "1.0.1"
814+ resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
815+ integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
816+ dependencies:
817+ collection-visit "^1.0.0"
818+ component-emitter "^1.2.1"
819+ get-value "^2.0.6"
820+ has-value "^1.0.0"
821+ isobject "^3.0.1"
822+ set-value "^2.0.0"
823+ to-object-path "^0.3.0"
824+ union-value "^1.0.0"
825+ unset-value "^1.0.0"
826+
827+call-bind@^1.0.0:
828+ version "1.0.2"
829+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
830+ integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
831+ dependencies:
832+ function-bind "^1.1.1"
833+ get-intrinsic "^1.0.2"
834+
835+call-me-maybe@^1.0.1:
836+ version "1.0.1"
837+ resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
838+ integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
839+
840+caller-callsite@^2.0.0:
841+ version "2.0.0"
842+ resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
843+ integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=
844+ dependencies:
845+ callsites "^2.0.0"
846+
847+caller-path@^2.0.0:
848+ version "2.0.0"
849+ resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4"
850+ integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=
851+ dependencies:
852+ caller-callsite "^2.0.0"
853+
854+callsites@^2.0.0:
855+ version "2.0.0"
856+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
857+ integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=
858+
859+callsites@^3.0.0:
860+ version "3.1.0"
861+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
862+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
863+
864+camelcase-keys@^4.0.0:
865+ version "4.2.0"
866+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77"
867+ integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=
868+ dependencies:
869+ camelcase "^4.1.0"
870+ map-obj "^2.0.0"
871+ quick-lru "^1.0.0"
872+
873+camelcase-keys@^6.2.2:
874+ version "6.2.2"
875+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
876+ integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
877+ dependencies:
878+ camelcase "^5.3.1"
879+ map-obj "^4.0.0"
880+ quick-lru "^4.0.1"
881+
882+camelcase@^3.0.0:
883+ version "3.0.0"
884+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
885+ integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
886+
887+camelcase@^4.1.0:
888+ version "4.1.0"
889+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
890+ integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
891+
892+camelcase@^5.0.0, camelcase@^5.3.1:
893+ version "5.3.1"
894+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
895+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
896+
897+caseless@~0.12.0:
898+ version "0.12.0"
899+ resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
900+ integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
901+
902+chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0:
903+ version "2.4.2"
904+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
905+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
906+ dependencies:
907+ ansi-styles "^3.2.1"
908+ escape-string-regexp "^1.0.5"
909+ supports-color "^5.3.0"
910+
911+chokidar@^2.0.0:
912+ version "2.1.8"
913+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
914+ integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
915+ dependencies:
916+ anymatch "^2.0.0"
917+ async-each "^1.0.1"
918+ braces "^2.3.2"
919+ glob-parent "^3.1.0"
920+ inherits "^2.0.3"
921+ is-binary-path "^1.0.0"
922+ is-glob "^4.0.0"
923+ normalize-path "^3.0.0"
924+ path-is-absolute "^1.0.0"
925+ readdirp "^2.2.1"
926+ upath "^1.1.1"
927+ optionalDependencies:
928+ fsevents "^1.2.7"
929+
930+class-utils@^0.3.5:
931+ version "0.3.6"
932+ resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
933+ integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
934+ dependencies:
935+ arr-union "^3.1.0"
936+ define-property "^0.2.5"
937+ isobject "^3.0.0"
938+ static-extend "^0.1.1"
939+
940+clean-stack@^2.0.0:
941+ version "2.2.0"
942+ resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
943+ integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
944+
945+cliui@^3.2.0:
946+ version "3.2.0"
947+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
948+ integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
949+ dependencies:
950+ string-width "^1.0.1"
951+ strip-ansi "^3.0.1"
952+ wrap-ansi "^2.0.0"
953+
954+clone-buffer@^1.0.0:
955+ version "1.0.0"
956+ resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
957+ integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
958+
959+clone-stats@^1.0.0:
960+ version "1.0.0"
961+ resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
962+ integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=
963+
964+clone@^2.1.1:
965+ version "2.1.2"
966+ resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
967+ integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
968+
969+cloneable-readable@^1.0.0:
970+ version "1.1.3"
971+ resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec"
972+ integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==
973+ dependencies:
974+ inherits "^2.0.1"
975+ process-nextick-args "^2.0.0"
976+ readable-stream "^2.3.5"
977+
978+code-point-at@^1.0.0:
979+ version "1.1.0"
980+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
981+ integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
982+
983+collection-map@^1.0.0:
984+ version "1.0.0"
985+ resolved "https://registry.yarnpkg.com/collection-map/-/collection-map-1.0.0.tgz#aea0f06f8d26c780c2b75494385544b2255af18c"
986+ integrity sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=
987+ dependencies:
988+ arr-map "^2.0.2"
989+ for-own "^1.0.0"
990+ make-iterator "^1.0.0"
991+
992+collection-visit@^1.0.0:
993+ version "1.0.0"
994+ resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
995+ integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
996+ dependencies:
997+ map-visit "^1.0.0"
998+ object-visit "^1.0.0"
999+
1000+color-convert@^1.9.0:
1001+ version "1.9.3"
1002+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
1003+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
1004+ dependencies:
1005+ color-name "1.1.3"
1006+
1007+color-name@1.1.3:
1008+ version "1.1.3"
1009+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
1010+ integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
1011+
1012+color-support@^1.1.3:
1013+ version "1.1.3"
1014+ resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
1015+ integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
1016+
1017+combined-stream@^1.0.6, combined-stream@~1.0.6:
1018+ version "1.0.8"
1019+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
1020+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
1021+ dependencies:
1022+ delayed-stream "~1.0.0"
1023+
1024+commander@^2.12.1, commander@^2.7.1:
1025+ version "2.20.3"
1026+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
1027+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
1028+
1029+commander@^5.0.0:
1030+ version "5.1.0"
1031+ resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
1032+ integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
1033+
1034+commander@^6.1.0:
1035+ version "6.2.1"
1036+ resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
1037+ integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
1038+
1039+compare-func@^1.3.1:
1040+ version "1.3.4"
1041+ resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.4.tgz#6b07c4c5e8341119baf44578085bda0f4a823516"
1042+ integrity sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q==
1043+ dependencies:
1044+ array-ify "^1.0.0"
1045+ dot-prop "^3.0.0"
1046+
1047+compare-func@^2.0.0:
1048+ version "2.0.0"
1049+ resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3"
1050+ integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==
1051+ dependencies:
1052+ array-ify "^1.0.0"
1053+ dot-prop "^5.1.0"
1054+
1055+component-emitter@^1.2.1:
1056+ version "1.3.0"
1057+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
1058+ integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
1059+
1060+concat-map@0.0.1:
1061+ version "0.0.1"
1062+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
1063+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
1064+
1065+concat-stream@^1.6.0:
1066+ version "1.6.2"
1067+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
1068+ integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
1069+ dependencies:
1070+ buffer-from "^1.0.0"
1071+ inherits "^2.0.3"
1072+ readable-stream "^2.2.2"
1073+ typedarray "^0.0.6"
1074+
1075+concat-stream@^2.0.0:
1076+ version "2.0.0"
1077+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1"
1078+ integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
1079+ dependencies:
1080+ buffer-from "^1.0.0"
1081+ inherits "^2.0.3"
1082+ readable-stream "^3.0.2"
1083+ typedarray "^0.0.6"
1084+
1085+content-disposition@0.5.3:
1086+ version "0.5.3"
1087+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
1088+ integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
1089+ dependencies:
1090+ safe-buffer "5.1.2"
1091+
1092+content-type@~1.0.4:
1093+ version "1.0.4"
1094+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
1095+ integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
1096+
1097+conventional-changelog-angular@^1.3.3:
1098+ version "1.6.6"
1099+ resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-1.6.6.tgz#b27f2b315c16d0a1f23eb181309d0e6a4698ea0f"
1100+ integrity sha512-suQnFSqCxRwyBxY68pYTsFkG0taIdinHLNEAX5ivtw8bCRnIgnpvcHmlR/yjUyZIrNPYAoXlY1WiEKWgSE4BNg==
1101+ dependencies:
1102+ compare-func "^1.3.1"
1103+ q "^1.5.1"
1104+
1105+conventional-changelog-angular@^5.0.12:
1106+ version "5.0.12"
1107+ resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz#c979b8b921cbfe26402eb3da5bbfda02d865a2b9"
1108+ integrity sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw==
1109+ dependencies:
1110+ compare-func "^2.0.0"
1111+ q "^1.5.1"
1112+
1113+conventional-changelog-atom@^2.0.8:
1114+ version "2.0.8"
1115+ resolved "https://registry.yarnpkg.com/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz#a759ec61c22d1c1196925fca88fe3ae89fd7d8de"
1116+ integrity sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==
1117+ dependencies:
1118+ q "^1.5.1"
1119+
1120+conventional-changelog-codemirror@^2.0.8:
1121+ version "2.0.8"
1122+ resolved "https://registry.yarnpkg.com/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz#398e9530f08ce34ec4640af98eeaf3022eb1f7dc"
1123+ integrity sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==
1124+ dependencies:
1125+ q "^1.5.1"
1126+
1127+conventional-changelog-conventionalcommits@4.2.1:
1128+ version "4.2.1"
1129+ resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.1.tgz#d6cb2e2c5d7bfca044a08b9dba84b4082e1a1bd9"
1130+ integrity sha512-vC02KucnkNNap+foDKFm7BVUSDAXktXrUJqGszUuYnt6T0J2azsbYz/w9TDc3VsrW2v6JOtiQWVcgZnporHr4Q==
1131+ dependencies:
1132+ compare-func "^1.3.1"
1133+ lodash "^4.2.1"
1134+ q "^1.5.1"
1135+
1136+conventional-changelog-conventionalcommits@^4.5.0:
1137+ version "4.6.0"
1138+ resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.0.tgz#7fc17211dbca160acf24687bd2fdd5fd767750eb"
1139+ integrity sha512-sj9tj3z5cnHaSJCYObA9nISf7eq/YjscLPoq6nmew4SiOjxqL2KRpK20fjnjVbpNDjJ2HR3MoVcWKXwbVvzS0A==
1140+ dependencies:
1141+ compare-func "^2.0.0"
1142+ lodash "^4.17.15"
1143+ q "^1.5.1"
1144+
1145+conventional-changelog-core@^4.2.1:
1146+ version "4.2.3"
1147+ resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.3.tgz#ce44d4bbba4032e3dc14c00fcd5b53fc00b66433"
1148+ integrity sha512-MwnZjIoMRL3jtPH5GywVNqetGILC7g6RQFvdb8LRU/fA/338JbeWAku3PZ8yQ+mtVRViiISqJlb0sOz0htBZig==
1149+ dependencies:
1150+ add-stream "^1.0.0"
1151+ conventional-changelog-writer "^5.0.0"
1152+ conventional-commits-parser "^3.2.0"
1153+ dateformat "^3.0.0"
1154+ get-pkg-repo "^4.0.0"
1155+ git-raw-commits "^2.0.8"
1156+ git-remote-origin-url "^2.0.0"
1157+ git-semver-tags "^4.1.1"
1158+ lodash "^4.17.15"
1159+ normalize-package-data "^3.0.0"
1160+ q "^1.5.1"
1161+ read-pkg "^3.0.0"
1162+ read-pkg-up "^3.0.0"
1163+ through2 "^4.0.0"
1164+
1165+conventional-changelog-ember@^2.0.9:
1166+ version "2.0.9"
1167+ resolved "https://registry.yarnpkg.com/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz#619b37ec708be9e74a220f4dcf79212ae1c92962"
1168+ integrity sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==
1169+ dependencies:
1170+ q "^1.5.1"
1171+
1172+conventional-changelog-eslint@^3.0.9:
1173+ version "3.0.9"
1174+ resolved "https://registry.yarnpkg.com/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz#689bd0a470e02f7baafe21a495880deea18b7cdb"
1175+ integrity sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==
1176+ dependencies:
1177+ q "^1.5.1"
1178+
1179+conventional-changelog-express@^2.0.6:
1180+ version "2.0.6"
1181+ resolved "https://registry.yarnpkg.com/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz#420c9d92a347b72a91544750bffa9387665a6ee8"
1182+ integrity sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==
1183+ dependencies:
1184+ q "^1.5.1"
1185+
1186+conventional-changelog-jquery@^3.0.11:
1187+ version "3.0.11"
1188+ resolved "https://registry.yarnpkg.com/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz#d142207400f51c9e5bb588596598e24bba8994bf"
1189+ integrity sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==
1190+ dependencies:
1191+ q "^1.5.1"
1192+
1193+conventional-changelog-jshint@^2.0.9:
1194+ version "2.0.9"
1195+ resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz#f2d7f23e6acd4927a238555d92c09b50fe3852ff"
1196+ integrity sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==
1197+ dependencies:
1198+ compare-func "^2.0.0"
1199+ q "^1.5.1"
1200+
1201+conventional-changelog-preset-loader@^2.3.4:
1202+ version "2.3.4"
1203+ resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c"
1204+ integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==
1205+
1206+conventional-changelog-writer@^5.0.0:
1207+ version "5.0.0"
1208+ resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz#c4042f3f1542f2f41d7d2e0d6cad23aba8df8eec"
1209+ integrity sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g==
1210+ dependencies:
1211+ conventional-commits-filter "^2.0.7"
1212+ dateformat "^3.0.0"
1213+ handlebars "^4.7.6"
1214+ json-stringify-safe "^5.0.1"
1215+ lodash "^4.17.15"
1216+ meow "^8.0.0"
1217+ semver "^6.0.0"
1218+ split "^1.0.0"
1219+ through2 "^4.0.0"
1220+
1221+conventional-changelog@^3.1.24:
1222+ version "3.1.24"
1223+ resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-3.1.24.tgz#ebd180b0fd1b2e1f0095c4b04fd088698348a464"
1224+ integrity sha512-ed6k8PO00UVvhExYohroVPXcOJ/K1N0/drJHx/faTH37OIZthlecuLIRX/T6uOp682CAoVoFpu+sSEaeuH6Asg==
1225+ dependencies:
1226+ conventional-changelog-angular "^5.0.12"
1227+ conventional-changelog-atom "^2.0.8"
1228+ conventional-changelog-codemirror "^2.0.8"
1229+ conventional-changelog-conventionalcommits "^4.5.0"
1230+ conventional-changelog-core "^4.2.1"
1231+ conventional-changelog-ember "^2.0.9"
1232+ conventional-changelog-eslint "^3.0.9"
1233+ conventional-changelog-express "^2.0.6"
1234+ conventional-changelog-jquery "^3.0.11"
1235+ conventional-changelog-jshint "^2.0.9"
1236+ conventional-changelog-preset-loader "^2.3.4"
1237+
1238+conventional-commits-filter@^2.0.7:
1239+ version "2.0.7"
1240+ resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3"
1241+ integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==
1242+ dependencies:
1243+ lodash.ismatch "^4.4.0"
1244+ modify-values "^1.0.0"
1245+
1246+conventional-commits-parser@^3.0.0, conventional-commits-parser@^3.2.0:
1247+ version "3.2.1"
1248+ resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2"
1249+ integrity sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA==
1250+ dependencies:
1251+ JSONStream "^1.0.4"
1252+ is-text-path "^1.0.1"
1253+ lodash "^4.17.15"
1254+ meow "^8.0.0"
1255+ split2 "^3.0.0"
1256+ through2 "^4.0.0"
1257+ trim-off-newlines "^1.0.0"
1258+
1259+convert-source-map@^1.5.0:
1260+ version "1.8.0"
1261+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
1262+ integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
1263+ dependencies:
1264+ safe-buffer "~5.1.1"
1265+
1266+cookie-signature@1.0.6:
1267+ version "1.0.6"
1268+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
1269+ integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
1270+
1271+cookie@0.4.0:
1272+ version "0.4.0"
1273+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
1274+ integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
1275+
1276+copy-descriptor@^0.1.0:
1277+ version "0.1.1"
1278+ resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
1279+ integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
1280+
1281+copy-props@^2.0.1:
1282+ version "2.0.5"
1283+ resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.5.tgz#03cf9ae328d4ebb36f8f1d804448a6af9ee3f2d2"
1284+ integrity sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==
1285+ dependencies:
1286+ each-props "^1.3.2"
1287+ is-plain-object "^5.0.0"
1288+
1289+core-js@^2.4.0, core-js@^2.5.0:
1290+ version "2.6.12"
1291+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
1292+ integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
1293+
1294+core-util-is@1.0.2, core-util-is@~1.0.0:
1295+ version "1.0.2"
1296+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
1297+ integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
1298+
1299+cosmiconfig@^5.2.0:
1300+ version "5.2.1"
1301+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
1302+ integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
1303+ dependencies:
1304+ import-fresh "^2.0.0"
1305+ is-directory "^0.3.1"
1306+ js-yaml "^3.13.1"
1307+ parse-json "^4.0.0"
1308+
1309+currently-unhandled@^0.4.1:
1310+ version "0.4.1"
1311+ resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
1312+ integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
1313+ dependencies:
1314+ array-find-index "^1.0.1"
1315+
1316+d@1, d@^1.0.1:
1317+ version "1.0.1"
1318+ resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
1319+ integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
1320+ dependencies:
1321+ es5-ext "^0.10.50"
1322+ type "^1.0.1"
1323+
1324+dargs@^7.0.0:
1325+ version "7.0.0"
1326+ resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc"
1327+ integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==
1328+
1329+dashdash@^1.12.0:
1330+ version "1.14.1"
1331+ resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
1332+ integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
1333+ dependencies:
1334+ assert-plus "^1.0.0"
1335+
1336+dateformat@^3.0.0:
1337+ version "3.0.3"
1338+ resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
1339+ integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
1340+
1341+debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
1342+ version "2.6.9"
1343+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
1344+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
1345+ dependencies:
1346+ ms "2.0.0"
1347+
1348+decamelize-keys@^1.0.0, decamelize-keys@^1.1.0:
1349+ version "1.1.0"
1350+ resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
1351+ integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=
1352+ dependencies:
1353+ decamelize "^1.1.0"
1354+ map-obj "^1.0.0"
1355+
1356+decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0:
1357+ version "1.2.0"
1358+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
1359+ integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
1360+
1361+decode-uri-component@^0.2.0:
1362+ version "0.2.0"
1363+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
1364+ integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
1365+
1366+default-compare@^1.0.0:
1367+ version "1.0.0"
1368+ resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f"
1369+ integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==
1370+ dependencies:
1371+ kind-of "^5.0.2"
1372+
1373+default-resolution@^2.0.0:
1374+ version "2.0.0"
1375+ resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684"
1376+ integrity sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=
1377+
1378+define-properties@^1.1.3:
1379+ version "1.1.3"
1380+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
1381+ integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
1382+ dependencies:
1383+ object-keys "^1.0.12"
1384+
1385+define-property@^0.2.5:
1386+ version "0.2.5"
1387+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
1388+ integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
1389+ dependencies:
1390+ is-descriptor "^0.1.0"
1391+
1392+define-property@^1.0.0:
1393+ version "1.0.0"
1394+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
1395+ integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
1396+ dependencies:
1397+ is-descriptor "^1.0.0"
1398+
1399+define-property@^2.0.2:
1400+ version "2.0.2"
1401+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
1402+ integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
1403+ dependencies:
1404+ is-descriptor "^1.0.2"
1405+ isobject "^3.0.1"
1406+
1407+del@^6.0.0:
1408+ version "6.0.0"
1409+ resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952"
1410+ integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==
1411+ dependencies:
1412+ globby "^11.0.1"
1413+ graceful-fs "^4.2.4"
1414+ is-glob "^4.0.1"
1415+ is-path-cwd "^2.2.0"
1416+ is-path-inside "^3.0.2"
1417+ p-map "^4.0.0"
1418+ rimraf "^3.0.2"
1419+ slash "^3.0.0"
1420+
1421+delayed-stream@~1.0.0:
1422+ version "1.0.0"
1423+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
1424+ integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
1425+
1426+depd@~1.1.2:
1427+ version "1.1.2"
1428+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
1429+ integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
1430+
1431+destroy@~1.0.4:
1432+ version "1.0.4"
1433+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
1434+ integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
1435+
1436+detect-file@^1.0.0:
1437+ version "1.0.0"
1438+ resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
1439+ integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
1440+
1441+diff@^4.0.1:
1442+ version "4.0.2"
1443+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
1444+ integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
1445+
1446+dir-glob@^3.0.1:
1447+ version "3.0.1"
1448+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
1449+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
1450+ dependencies:
1451+ path-type "^4.0.0"
1452+
1453+dot-prop@^3.0.0:
1454+ version "3.0.0"
1455+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
1456+ integrity sha1-G3CK8JSknJoOfbyteQq6U52sEXc=
1457+ dependencies:
1458+ is-obj "^1.0.0"
1459+
1460+dot-prop@^5.1.0:
1461+ version "5.3.0"
1462+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88"
1463+ integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
1464+ dependencies:
1465+ is-obj "^2.0.0"
1466+
1467+duplexify@^3.6.0:
1468+ version "3.7.1"
1469+ resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
1470+ integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
1471+ dependencies:
1472+ end-of-stream "^1.0.0"
1473+ inherits "^2.0.1"
1474+ readable-stream "^2.0.0"
1475+ stream-shift "^1.0.0"
1476+
1477+each-props@^1.3.2:
1478+ version "1.3.2"
1479+ resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333"
1480+ integrity sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==
1481+ dependencies:
1482+ is-plain-object "^2.0.1"
1483+ object.defaults "^1.1.0"
1484+
1485+ecc-jsbn@~0.1.1:
1486+ version "0.1.2"
1487+ resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
1488+ integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
1489+ dependencies:
1490+ jsbn "~0.1.0"
1491+ safer-buffer "^2.1.0"
1492+
1493+ee-first@1.1.1:
1494+ version "1.1.1"
1495+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
1496+ integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
1497+
1498+encodeurl@~1.0.2:
1499+ version "1.0.2"
1500+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
1501+ integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
1502+
1503+end-of-stream@^1.0.0, end-of-stream@^1.1.0:
1504+ version "1.4.4"
1505+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
1506+ integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
1507+ dependencies:
1508+ once "^1.4.0"
1509+
1510+error-ex@^1.2.0, error-ex@^1.3.1:
1511+ version "1.3.2"
1512+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
1513+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
1514+ dependencies:
1515+ is-arrayish "^0.2.1"
1516+
1517+es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50:
1518+ version "0.10.53"
1519+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
1520+ integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
1521+ dependencies:
1522+ es6-iterator "~2.0.3"
1523+ es6-symbol "~3.1.3"
1524+ next-tick "~1.0.0"
1525+
1526+es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.3:
1527+ version "2.0.3"
1528+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
1529+ integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
1530+ dependencies:
1531+ d "1"
1532+ es5-ext "^0.10.35"
1533+ es6-symbol "^3.1.1"
1534+
1535+es6-symbol@^3.1.1, es6-symbol@~3.1.3:
1536+ version "3.1.3"
1537+ resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
1538+ integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
1539+ dependencies:
1540+ d "^1.0.1"
1541+ ext "^1.1.2"
1542+
1543+es6-weak-map@^2.0.1:
1544+ version "2.0.3"
1545+ resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53"
1546+ integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==
1547+ dependencies:
1548+ d "1"
1549+ es5-ext "^0.10.46"
1550+ es6-iterator "^2.0.3"
1551+ es6-symbol "^3.1.1"
1552+
1553+escape-html@~1.0.3:
1554+ version "1.0.3"
1555+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
1556+ integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
1557+
1558+escape-string-regexp@^1.0.5:
1559+ version "1.0.5"
1560+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
1561+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
1562+
1563+esprima@^4.0.0:
1564+ version "4.0.1"
1565+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
1566+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
1567+
1568+etag@~1.8.1:
1569+ version "1.8.1"
1570+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
1571+ integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
1572+
1573+expand-brackets@^2.1.4:
1574+ version "2.1.4"
1575+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
1576+ integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
1577+ dependencies:
1578+ debug "^2.3.3"
1579+ define-property "^0.2.5"
1580+ extend-shallow "^2.0.1"
1581+ posix-character-classes "^0.1.0"
1582+ regex-not "^1.0.0"
1583+ snapdragon "^0.8.1"
1584+ to-regex "^3.0.1"
1585+
1586+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
1587+ version "2.0.2"
1588+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
1589+ integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
1590+ dependencies:
1591+ homedir-polyfill "^1.0.1"
1592+
1593+express@^4.17.1:
1594+ version "4.17.1"
1595+ resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
1596+ integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
1597+ dependencies:
1598+ accepts "~1.3.7"
1599+ array-flatten "1.1.1"
1600+ body-parser "1.19.0"
1601+ content-disposition "0.5.3"
1602+ content-type "~1.0.4"
1603+ cookie "0.4.0"
1604+ cookie-signature "1.0.6"
1605+ debug "2.6.9"
1606+ depd "~1.1.2"
1607+ encodeurl "~1.0.2"
1608+ escape-html "~1.0.3"
1609+ etag "~1.8.1"
1610+ finalhandler "~1.1.2"
1611+ fresh "0.5.2"
1612+ merge-descriptors "1.0.1"
1613+ methods "~1.1.2"
1614+ on-finished "~2.3.0"
1615+ parseurl "~1.3.3"
1616+ path-to-regexp "0.1.7"
1617+ proxy-addr "~2.0.5"
1618+ qs "6.7.0"
1619+ range-parser "~1.2.1"
1620+ safe-buffer "5.1.2"
1621+ send "0.17.1"
1622+ serve-static "1.14.1"
1623+ setprototypeof "1.1.1"
1624+ statuses "~1.5.0"
1625+ type-is "~1.6.18"
1626+ utils-merge "1.0.1"
1627+ vary "~1.1.2"
1628+
1629+ext@^1.1.2:
1630+ version "1.4.0"
1631+ resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
1632+ integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==
1633+ dependencies:
1634+ type "^2.0.0"
1635+
1636+extend-shallow@^1.1.2:
1637+ version "1.1.4"
1638+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071"
1639+ integrity sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=
1640+ dependencies:
1641+ kind-of "^1.1.0"
1642+
1643+extend-shallow@^2.0.1:
1644+ version "2.0.1"
1645+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
1646+ integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
1647+ dependencies:
1648+ is-extendable "^0.1.0"
1649+
1650+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
1651+ version "3.0.2"
1652+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
1653+ integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
1654+ dependencies:
1655+ assign-symbols "^1.0.0"
1656+ is-extendable "^1.0.1"
1657+
1658+extend@^3.0.0, extend@~3.0.2:
1659+ version "3.0.2"
1660+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
1661+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
1662+
1663+extglob@^2.0.4:
1664+ version "2.0.4"
1665+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
1666+ integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
1667+ dependencies:
1668+ array-unique "^0.3.2"
1669+ define-property "^1.0.0"
1670+ expand-brackets "^2.1.4"
1671+ extend-shallow "^2.0.1"
1672+ fragment-cache "^0.2.1"
1673+ regex-not "^1.0.0"
1674+ snapdragon "^0.8.1"
1675+ to-regex "^3.0.1"
1676+
1677+extsprintf@1.3.0:
1678+ version "1.3.0"
1679+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
1680+ integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
1681+
1682+extsprintf@^1.2.0:
1683+ version "1.4.0"
1684+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
1685+ integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
1686+
1687+fancy-log@1.3.3, fancy-log@^1.3.2:
1688+ version "1.3.3"
1689+ resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7"
1690+ integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==
1691+ dependencies:
1692+ ansi-gray "^0.1.1"
1693+ color-support "^1.1.3"
1694+ parse-node-version "^1.0.0"
1695+ time-stamp "^1.0.0"
1696+
1697+fast-deep-equal@^3.1.1:
1698+ version "3.1.3"
1699+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
1700+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
1701+
1702+fast-glob@^3.1.1:
1703+ version "3.2.6"
1704+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.6.tgz#434dd9529845176ea049acc9343e8282765c6e1a"
1705+ integrity sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==
1706+ dependencies:
1707+ "@nodelib/fs.stat" "^2.0.2"
1708+ "@nodelib/fs.walk" "^1.2.3"
1709+ glob-parent "^5.1.2"
1710+ merge2 "^1.3.0"
1711+ micromatch "^4.0.4"
1712+
1713+fast-json-stable-stringify@^2.0.0:
1714+ version "2.1.0"
1715+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
1716+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
1717+
1718+fast-levenshtein@^1.0.0:
1719+ version "1.1.4"
1720+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz#e6a754cc8f15e58987aa9cbd27af66fd6f4e5af9"
1721+ integrity sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=
1722+
1723+fastq@^1.6.0:
1724+ version "1.11.1"
1725+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.1.tgz#5d8175aae17db61947f8b162cfc7f63264d22807"
1726+ integrity sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==
1727+ dependencies:
1728+ reusify "^1.0.4"
1729+
1730+file-uri-to-path@1.0.0:
1731+ version "1.0.0"
1732+ resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
1733+ integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
1734+
1735+fill-range@^4.0.0:
1736+ version "4.0.0"
1737+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
1738+ integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
1739+ dependencies:
1740+ extend-shallow "^2.0.1"
1741+ is-number "^3.0.0"
1742+ repeat-string "^1.6.1"
1743+ to-regex-range "^2.1.0"
1744+
1745+fill-range@^7.0.1:
1746+ version "7.0.1"
1747+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
1748+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
1749+ dependencies:
1750+ to-regex-range "^5.0.1"
1751+
1752+finalhandler@~1.1.2:
1753+ version "1.1.2"
1754+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
1755+ integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
1756+ dependencies:
1757+ debug "2.6.9"
1758+ encodeurl "~1.0.2"
1759+ escape-html "~1.0.3"
1760+ on-finished "~2.3.0"
1761+ parseurl "~1.3.3"
1762+ statuses "~1.5.0"
1763+ unpipe "~1.0.0"
1764+
1765+find-up@^1.0.0:
1766+ version "1.1.2"
1767+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
1768+ integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
1769+ dependencies:
1770+ path-exists "^2.0.0"
1771+ pinkie-promise "^2.0.0"
1772+
1773+find-up@^2.0.0:
1774+ version "2.1.0"
1775+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
1776+ integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
1777+ dependencies:
1778+ locate-path "^2.0.0"
1779+
1780+find-up@^4.0.0, find-up@^4.1.0:
1781+ version "4.1.0"
1782+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
1783+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
1784+ dependencies:
1785+ locate-path "^5.0.0"
1786+ path-exists "^4.0.0"
1787+
1788+findup-sync@^2.0.0:
1789+ version "2.0.0"
1790+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
1791+ integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=
1792+ dependencies:
1793+ detect-file "^1.0.0"
1794+ is-glob "^3.1.0"
1795+ micromatch "^3.0.4"
1796+ resolve-dir "^1.0.1"
1797+
1798+findup-sync@^3.0.0:
1799+ version "3.0.0"
1800+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1"
1801+ integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==
1802+ dependencies:
1803+ detect-file "^1.0.0"
1804+ is-glob "^4.0.0"
1805+ micromatch "^3.0.4"
1806+ resolve-dir "^1.0.1"
1807+
1808+fined@^1.0.1:
1809+ version "1.2.0"
1810+ resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b"
1811+ integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==
1812+ dependencies:
1813+ expand-tilde "^2.0.2"
1814+ is-plain-object "^2.0.3"
1815+ object.defaults "^1.1.0"
1816+ object.pick "^1.2.0"
1817+ parse-filepath "^1.0.1"
1818+
1819+first-chunk-stream@^2.0.0:
1820+ version "2.0.0"
1821+ resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70"
1822+ integrity sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=
1823+ dependencies:
1824+ readable-stream "^2.0.2"
1825+
1826+flagged-respawn@^1.0.0:
1827+ version "1.0.1"
1828+ resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41"
1829+ integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==
1830+
1831+flush-write-stream@^1.0.2:
1832+ version "1.1.1"
1833+ resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
1834+ integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==
1835+ dependencies:
1836+ inherits "^2.0.3"
1837+ readable-stream "^2.3.6"
1838+
1839+for-in@^1.0.1, for-in@^1.0.2:
1840+ version "1.0.2"
1841+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
1842+ integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
1843+
1844+for-own@^1.0.0:
1845+ version "1.0.0"
1846+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
1847+ integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
1848+ dependencies:
1849+ for-in "^1.0.1"
1850+
1851+forever-agent@~0.6.1:
1852+ version "0.6.1"
1853+ resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
1854+ integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
1855+
1856+form-data@^2.5.0:
1857+ version "2.5.1"
1858+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4"
1859+ integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==
1860+ dependencies:
1861+ asynckit "^0.4.0"
1862+ combined-stream "^1.0.6"
1863+ mime-types "^2.1.12"
1864+
1865+form-data@~2.3.2:
1866+ version "2.3.3"
1867+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
1868+ integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
1869+ dependencies:
1870+ asynckit "^0.4.0"
1871+ combined-stream "^1.0.6"
1872+ mime-types "^2.1.12"
1873+
1874+forwarded@0.2.0:
1875+ version "0.2.0"
1876+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
1877+ integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
1878+
1879+fragment-cache@^0.2.1:
1880+ version "0.2.1"
1881+ resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
1882+ integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
1883+ dependencies:
1884+ map-cache "^0.2.2"
1885+
1886+fresh@0.5.2:
1887+ version "0.5.2"
1888+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
1889+ integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
1890+
1891+fs-mkdirp-stream@^1.0.0:
1892+ version "1.0.0"
1893+ resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb"
1894+ integrity sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=
1895+ dependencies:
1896+ graceful-fs "^4.1.11"
1897+ through2 "^2.0.3"
1898+
1899+fs.realpath@^1.0.0:
1900+ version "1.0.0"
1901+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
1902+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
1903+
1904+fsevents@^1.2.7:
1905+ version "1.2.13"
1906+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
1907+ integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==
1908+ dependencies:
1909+ bindings "^1.5.0"
1910+ nan "^2.12.1"
1911+
1912+function-bind@^1.1.1:
1913+ version "1.1.1"
1914+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
1915+ integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
1916+
1917+get-caller-file@^1.0.1:
1918+ version "1.0.3"
1919+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
1920+ integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
1921+
1922+get-intrinsic@^1.0.2:
1923+ version "1.1.1"
1924+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
1925+ integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
1926+ dependencies:
1927+ function-bind "^1.1.1"
1928+ has "^1.0.3"
1929+ has-symbols "^1.0.1"
1930+
1931+get-pkg-repo@^4.0.0:
1932+ version "4.1.2"
1933+ resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.1.2.tgz#c4ffd60015cf091be666a0212753fc158f01a4c0"
1934+ integrity sha512-/FjamZL9cBYllEbReZkxF2IMh80d8TJoC4e3bmLNif8ibHw95aj0N/tzqK0kZz9eU/3w3dL6lF4fnnX/sDdW3A==
1935+ dependencies:
1936+ "@hutson/parse-repository-url" "^3.0.0"
1937+ hosted-git-info "^4.0.0"
1938+ meow "^7.0.0"
1939+ through2 "^2.0.0"
1940+
1941+get-stdin@7.0.0:
1942+ version "7.0.0"
1943+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6"
1944+ integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==
1945+
1946+get-value@^2.0.3, get-value@^2.0.6:
1947+ version "2.0.6"
1948+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
1949+ integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
1950+
1951+getpass@^0.1.1:
1952+ version "0.1.7"
1953+ resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
1954+ integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
1955+ dependencies:
1956+ assert-plus "^1.0.0"
1957+
1958+git-raw-commits@^2.0.0, git-raw-commits@^2.0.8:
1959+ version "2.0.10"
1960+ resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1"
1961+ integrity sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ==
1962+ dependencies:
1963+ dargs "^7.0.0"
1964+ lodash "^4.17.15"
1965+ meow "^8.0.0"
1966+ split2 "^3.0.0"
1967+ through2 "^4.0.0"
1968+
1969+git-remote-origin-url@^2.0.0:
1970+ version "2.0.0"
1971+ resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f"
1972+ integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=
1973+ dependencies:
1974+ gitconfiglocal "^1.0.0"
1975+ pify "^2.3.0"
1976+
1977+git-semver-tags@^4.1.1:
1978+ version "4.1.1"
1979+ resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780"
1980+ integrity sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==
1981+ dependencies:
1982+ meow "^8.0.0"
1983+ semver "^6.0.0"
1984+
1985+gitconfiglocal@^1.0.0:
1986+ version "1.0.0"
1987+ resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b"
1988+ integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=
1989+ dependencies:
1990+ ini "^1.3.2"
1991+
1992+glob-parent@^3.1.0:
1993+ version "3.1.0"
1994+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
1995+ integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
1996+ dependencies:
1997+ is-glob "^3.1.0"
1998+ path-dirname "^1.0.0"
1999+
2000+glob-parent@^5.1.2:
2001+ version "5.1.2"
2002+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
2003+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
2004+ dependencies:
2005+ is-glob "^4.0.1"
2006+
2007+glob-stream@^6.1.0:
2008+ version "6.1.0"
2009+ resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4"
2010+ integrity sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=
2011+ dependencies:
2012+ extend "^3.0.0"
2013+ glob "^7.1.1"
2014+ glob-parent "^3.1.0"
2015+ is-negated-glob "^1.0.0"
2016+ ordered-read-streams "^1.0.0"
2017+ pumpify "^1.3.5"
2018+ readable-stream "^2.1.5"
2019+ remove-trailing-separator "^1.0.1"
2020+ to-absolute-glob "^2.0.0"
2021+ unique-stream "^2.0.2"
2022+
2023+glob-watcher@^5.0.3:
2024+ version "5.0.5"
2025+ resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-5.0.5.tgz#aa6bce648332924d9a8489be41e3e5c52d4186dc"
2026+ integrity sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==
2027+ dependencies:
2028+ anymatch "^2.0.0"
2029+ async-done "^1.2.0"
2030+ chokidar "^2.0.0"
2031+ is-negated-glob "^1.0.0"
2032+ just-debounce "^1.0.0"
2033+ normalize-path "^3.0.0"
2034+ object.defaults "^1.1.0"
2035+
2036+glob@^7.1.1, glob@^7.1.3, glob@^7.1.6:
2037+ version "7.1.7"
2038+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
2039+ integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
2040+ dependencies:
2041+ fs.realpath "^1.0.0"
2042+ inflight "^1.0.4"
2043+ inherits "2"
2044+ minimatch "^3.0.4"
2045+ once "^1.3.0"
2046+ path-is-absolute "^1.0.0"
2047+
2048+global-dirs@^0.1.1:
2049+ version "0.1.1"
2050+ resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
2051+ integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=
2052+ dependencies:
2053+ ini "^1.3.4"
2054+
2055+global-modules@^1.0.0:
2056+ version "1.0.0"
2057+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
2058+ integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
2059+ dependencies:
2060+ global-prefix "^1.0.1"
2061+ is-windows "^1.0.1"
2062+ resolve-dir "^1.0.0"
2063+
2064+global-prefix@^1.0.1:
2065+ version "1.0.2"
2066+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
2067+ integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
2068+ dependencies:
2069+ expand-tilde "^2.0.2"
2070+ homedir-polyfill "^1.0.1"
2071+ ini "^1.3.4"
2072+ is-windows "^1.0.1"
2073+ which "^1.2.14"
2074+
2075+globby@^11.0.1:
2076+ version "11.0.4"
2077+ resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
2078+ integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
2079+ dependencies:
2080+ array-union "^2.1.0"
2081+ dir-glob "^3.0.1"
2082+ fast-glob "^3.1.1"
2083+ ignore "^5.1.4"
2084+ merge2 "^1.3.0"
2085+ slash "^3.0.0"
2086+
2087+glogg@^1.0.0:
2088+ version "1.0.2"
2089+ resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.2.tgz#2d7dd702beda22eb3bffadf880696da6d846313f"
2090+ integrity sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==
2091+ dependencies:
2092+ sparkles "^1.0.0"
2093+
2094+graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.4:
2095+ version "4.2.6"
2096+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
2097+ integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
2098+
2099+gulp-clean@^0.4.0:
2100+ version "0.4.0"
2101+ resolved "https://registry.yarnpkg.com/gulp-clean/-/gulp-clean-0.4.0.tgz#3bc25e7084e641bbd7bde057cf90c01c50d95950"
2102+ integrity sha512-DARK8rNMo4lHOFLGTiHEJdf19GuoBDHqGUaypz+fOhrvOs3iFO7ntdYtdpNxv+AzSJBx/JfypF0yEj9ks1IStQ==
2103+ dependencies:
2104+ fancy-log "^1.3.2"
2105+ plugin-error "^0.1.2"
2106+ rimraf "^2.6.2"
2107+ through2 "^2.0.3"
2108+ vinyl "^2.1.0"
2109+
2110+gulp-cli@^2.2.0:
2111+ version "2.3.0"
2112+ resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.3.0.tgz#ec0d380e29e52aa45e47977f0d32e18fd161122f"
2113+ integrity sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==
2114+ dependencies:
2115+ ansi-colors "^1.0.1"
2116+ archy "^1.0.0"
2117+ array-sort "^1.0.0"
2118+ color-support "^1.1.3"
2119+ concat-stream "^1.6.0"
2120+ copy-props "^2.0.1"
2121+ fancy-log "^1.3.2"
2122+ gulplog "^1.0.0"
2123+ interpret "^1.4.0"
2124+ isobject "^3.0.1"
2125+ liftoff "^3.1.0"
2126+ matchdep "^2.0.0"
2127+ mute-stdout "^1.0.0"
2128+ pretty-hrtime "^1.0.0"
2129+ replace-homedir "^1.0.0"
2130+ semver-greatest-satisfied-range "^1.1.0"
2131+ v8flags "^3.2.0"
2132+ yargs "^7.1.0"
2133+
2134+gulp-conventional-changelog@^2.0.32:
2135+ version "2.0.35"
2136+ resolved "https://registry.yarnpkg.com/gulp-conventional-changelog/-/gulp-conventional-changelog-2.0.35.tgz#4ef5391ea46cca4b35fd262586e99de6d2c7017b"
2137+ integrity sha512-9khc2fGUc6qWUoQYnqck6/d28lIgP+49kOyYtOIJtp6pthqikSL1UQ8n+Erg9X/z83+z9OX1HWWuVIXbpxvdkw==
2138+ dependencies:
2139+ add-stream "^1.0.0"
2140+ concat-stream "^2.0.0"
2141+ conventional-changelog "^3.1.24"
2142+ fancy-log "^1.3.2"
2143+ object-assign "^4.0.1"
2144+ plugin-error "^1.0.1"
2145+ through2 "^4.0.0"
2146+
2147+gulp-filter@^6.0.0:
2148+ version "6.0.0"
2149+ resolved "https://registry.yarnpkg.com/gulp-filter/-/gulp-filter-6.0.0.tgz#9d69a408f1a9f60534264fb14464841f1b1746c2"
2150+ integrity sha512-veQFW93kf6jBdWdF/RxMEIlDK2mkjHyPftM381DID2C9ImTVngwYpyyThxm4/EpgcNOT37BLefzMOjEKbyYg0Q==
2151+ dependencies:
2152+ multimatch "^4.0.0"
2153+ plugin-error "^1.0.1"
2154+ streamfilter "^3.0.0"
2155+
2156+gulp-git@^2.10.1:
2157+ version "2.10.1"
2158+ resolved "https://registry.yarnpkg.com/gulp-git/-/gulp-git-2.10.1.tgz#218615c94bbf90660c1cb07a37054041d5e4f2eb"
2159+ integrity sha512-qiXYYDXchMZU/AWAgtphi4zbJb/0gXgfPw7TlZwu/7qPS3Bdcc3zbVe1B0xY9S8on6RQTmWoi+KaTGACIXQeNg==
2160+ dependencies:
2161+ any-shell-escape "^0.1.1"
2162+ fancy-log "^1.3.2"
2163+ lodash.template "^4.4.0"
2164+ plugin-error "^1.0.1"
2165+ require-dir "^1.0.0"
2166+ strip-bom-stream "^3.0.0"
2167+ through2 "^2.0.3"
2168+ vinyl "^2.0.1"
2169+
2170+gulp-jasmine@^4.0.0:
2171+ version "4.0.0"
2172+ resolved "https://registry.yarnpkg.com/gulp-jasmine/-/gulp-jasmine-4.0.0.tgz#efe566b8350f41a14f63ffaecc6ccdf8646709a9"
2173+ integrity sha512-0UqY2fA6RCdUDJDsVym3zXYSWmt0AV7YY/6PAeKb+oGTKEgS7zZOH5w/4gcSKs+2FXiWrucQwLDvtEKIDbpF4A==
2174+ dependencies:
2175+ arrify "^1.0.1"
2176+ jasmine "^3.1.0"
2177+ jasmine-terminal-reporter "^1.0.3"
2178+ plugin-error "^1.0.1"
2179+ through2 "^2.0.3"
2180+
2181+gulp-tslint@^8.1.4:
2182+ version "8.1.4"
2183+ resolved "https://registry.yarnpkg.com/gulp-tslint/-/gulp-tslint-8.1.4.tgz#8519ee25ff97aa749e691d4af0fdaccce5f01f7a"
2184+ integrity sha512-wBoZIEMJRz9urHwolsvQpngA9l931p6g/Liwz1b/KrsVP6jEBFZv/o0NS1TFCQZi/l8mXxz8+v3twhf4HOXxPQ==
2185+ dependencies:
2186+ "@types/fancy-log" "1.3.0"
2187+ ansi-colors "^1.0.1"
2188+ fancy-log "1.3.3"
2189+ map-stream "~0.0.7"
2190+ plugin-error "1.0.1"
2191+ through "~2.3.8"
2192+
2193+gulp-typescript@^5.0.1:
2194+ version "5.0.1"
2195+ resolved "https://registry.yarnpkg.com/gulp-typescript/-/gulp-typescript-5.0.1.tgz#96c6565a6eb31e08c2aae1c857b1a079e6226d94"
2196+ integrity sha512-YuMMlylyJtUSHG1/wuSVTrZp60k1dMEFKYOvDf7OvbAJWrDtxxD4oZon4ancdWwzjj30ztiidhe4VXJniF0pIQ==
2197+ dependencies:
2198+ ansi-colors "^3.0.5"
2199+ plugin-error "^1.0.1"
2200+ source-map "^0.7.3"
2201+ through2 "^3.0.0"
2202+ vinyl "^2.1.0"
2203+ vinyl-fs "^3.0.3"
2204+
2205+gulp@^4.0.2:
2206+ version "4.0.2"
2207+ resolved "https://registry.yarnpkg.com/gulp/-/gulp-4.0.2.tgz#543651070fd0f6ab0a0650c6a3e6ff5a7cb09caa"
2208+ integrity sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==
2209+ dependencies:
2210+ glob-watcher "^5.0.3"
2211+ gulp-cli "^2.2.0"
2212+ undertaker "^1.2.1"
2213+ vinyl-fs "^3.0.0"
2214+
2215+gulplog@^1.0.0:
2216+ version "1.0.0"
2217+ resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5"
2218+ integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U=
2219+ dependencies:
2220+ glogg "^1.0.0"
2221+
2222+handlebars@^4.7.6:
2223+ version "4.7.7"
2224+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
2225+ integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
2226+ dependencies:
2227+ minimist "^1.2.5"
2228+ neo-async "^2.6.0"
2229+ source-map "^0.6.1"
2230+ wordwrap "^1.0.0"
2231+ optionalDependencies:
2232+ uglify-js "^3.1.4"
2233+
2234+har-schema@^2.0.0:
2235+ version "2.0.0"
2236+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
2237+ integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
2238+
2239+har-validator@~5.1.3:
2240+ version "5.1.5"
2241+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
2242+ integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
2243+ dependencies:
2244+ ajv "^6.12.3"
2245+ har-schema "^2.0.0"
2246+
2247+hard-rejection@^2.1.0:
2248+ version "2.1.0"
2249+ resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
2250+ integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
2251+
2252+has-flag@^3.0.0:
2253+ version "3.0.0"
2254+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
2255+ integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
2256+
2257+has-symbols@^1.0.1:
2258+ version "1.0.2"
2259+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
2260+ integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
2261+
2262+has-value@^0.3.1:
2263+ version "0.3.1"
2264+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
2265+ integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
2266+ dependencies:
2267+ get-value "^2.0.3"
2268+ has-values "^0.1.4"
2269+ isobject "^2.0.0"
2270+
2271+has-value@^1.0.0:
2272+ version "1.0.0"
2273+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
2274+ integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
2275+ dependencies:
2276+ get-value "^2.0.6"
2277+ has-values "^1.0.0"
2278+ isobject "^3.0.0"
2279+
2280+has-values@^0.1.4:
2281+ version "0.1.4"
2282+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
2283+ integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
2284+
2285+has-values@^1.0.0:
2286+ version "1.0.0"
2287+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
2288+ integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
2289+ dependencies:
2290+ is-number "^3.0.0"
2291+ kind-of "^4.0.0"
2292+
2293+has@^1.0.3:
2294+ version "1.0.3"
2295+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
2296+ integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
2297+ dependencies:
2298+ function-bind "^1.1.1"
2299+
2300+homedir-polyfill@^1.0.1:
2301+ version "1.0.3"
2302+ resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
2303+ integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
2304+ dependencies:
2305+ parse-passwd "^1.0.0"
2306+
2307+hosted-git-info@^2.1.4:
2308+ version "2.8.9"
2309+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
2310+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
2311+
2312+hosted-git-info@^4.0.0, hosted-git-info@^4.0.1:
2313+ version "4.0.2"
2314+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961"
2315+ integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==
2316+ dependencies:
2317+ lru-cache "^6.0.0"
2318+
2319+http-errors@1.7.2:
2320+ version "1.7.2"
2321+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
2322+ integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
2323+ dependencies:
2324+ depd "~1.1.2"
2325+ inherits "2.0.3"
2326+ setprototypeof "1.1.1"
2327+ statuses ">= 1.5.0 < 2"
2328+ toidentifier "1.0.0"
2329+
2330+http-errors@~1.7.2:
2331+ version "1.7.3"
2332+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
2333+ integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
2334+ dependencies:
2335+ depd "~1.1.2"
2336+ inherits "2.0.4"
2337+ setprototypeof "1.1.1"
2338+ statuses ">= 1.5.0 < 2"
2339+ toidentifier "1.0.0"
2340+
2341+http-signature@~1.2.0:
2342+ version "1.2.0"
2343+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
2344+ integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
2345+ dependencies:
2346+ assert-plus "^1.0.0"
2347+ jsprim "^1.2.2"
2348+ sshpk "^1.7.0"
2349+
2350+iconv-lite@0.4.24:
2351+ version "0.4.24"
2352+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
2353+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
2354+ dependencies:
2355+ safer-buffer ">= 2.1.2 < 3"
2356+
2357+ignore@^5.1.4:
2358+ version "5.1.8"
2359+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
2360+ integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
2361+
2362+import-fresh@^2.0.0:
2363+ version "2.0.0"
2364+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
2365+ integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY=
2366+ dependencies:
2367+ caller-path "^2.0.0"
2368+ resolve-from "^3.0.0"
2369+
2370+import-fresh@^3.0.0:
2371+ version "3.3.0"
2372+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
2373+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
2374+ dependencies:
2375+ parent-module "^1.0.0"
2376+ resolve-from "^4.0.0"
2377+
2378+indent-string@^2.1.0:
2379+ version "2.1.0"
2380+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
2381+ integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
2382+ dependencies:
2383+ repeating "^2.0.0"
2384+
2385+indent-string@^3.0.0:
2386+ version "3.2.0"
2387+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
2388+ integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=
2389+
2390+indent-string@^4.0.0:
2391+ version "4.0.0"
2392+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
2393+ integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
2394+
2395+inflight@^1.0.4:
2396+ version "1.0.6"
2397+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
2398+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
2399+ dependencies:
2400+ once "^1.3.0"
2401+ wrappy "1"
2402+
2403+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
2404+ version "2.0.4"
2405+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
2406+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
2407+
2408+inherits@2.0.3:
2409+ version "2.0.3"
2410+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
2411+ integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
2412+
2413+ini@^1.3.2, ini@^1.3.4:
2414+ version "1.3.8"
2415+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
2416+ integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
2417+
2418+interpret@^1.4.0:
2419+ version "1.4.0"
2420+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
2421+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
2422+
2423+invert-kv@^1.0.0:
2424+ version "1.0.0"
2425+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
2426+ integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
2427+
2428+ipaddr.js@1.9.1:
2429+ version "1.9.1"
2430+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
2431+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
2432+
2433+is-absolute@^1.0.0:
2434+ version "1.0.0"
2435+ resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
2436+ integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==
2437+ dependencies:
2438+ is-relative "^1.0.0"
2439+ is-windows "^1.0.1"
2440+
2441+is-accessor-descriptor@^0.1.6:
2442+ version "0.1.6"
2443+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
2444+ integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
2445+ dependencies:
2446+ kind-of "^3.0.2"
2447+
2448+is-accessor-descriptor@^1.0.0:
2449+ version "1.0.0"
2450+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
2451+ integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
2452+ dependencies:
2453+ kind-of "^6.0.0"
2454+
2455+is-arrayish@^0.2.1:
2456+ version "0.2.1"
2457+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
2458+ integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
2459+
2460+is-binary-path@^1.0.0:
2461+ version "1.0.1"
2462+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
2463+ integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
2464+ dependencies:
2465+ binary-extensions "^1.0.0"
2466+
2467+is-buffer@^1.1.5:
2468+ version "1.1.6"
2469+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
2470+ integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
2471+
2472+is-core-module@^2.2.0:
2473+ version "2.4.0"
2474+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
2475+ integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==
2476+ dependencies:
2477+ has "^1.0.3"
2478+
2479+is-data-descriptor@^0.1.4:
2480+ version "0.1.4"
2481+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
2482+ integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
2483+ dependencies:
2484+ kind-of "^3.0.2"
2485+
2486+is-data-descriptor@^1.0.0:
2487+ version "1.0.0"
2488+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
2489+ integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
2490+ dependencies:
2491+ kind-of "^6.0.0"
2492+
2493+is-descriptor@^0.1.0:
2494+ version "0.1.6"
2495+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
2496+ integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
2497+ dependencies:
2498+ is-accessor-descriptor "^0.1.6"
2499+ is-data-descriptor "^0.1.4"
2500+ kind-of "^5.0.0"
2501+
2502+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
2503+ version "1.0.2"
2504+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
2505+ integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
2506+ dependencies:
2507+ is-accessor-descriptor "^1.0.0"
2508+ is-data-descriptor "^1.0.0"
2509+ kind-of "^6.0.2"
2510+
2511+is-directory@^0.3.1:
2512+ version "0.3.1"
2513+ resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
2514+ integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=
2515+
2516+is-extendable@^0.1.0, is-extendable@^0.1.1:
2517+ version "0.1.1"
2518+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
2519+ integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
2520+
2521+is-extendable@^1.0.1:
2522+ version "1.0.1"
2523+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
2524+ integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
2525+ dependencies:
2526+ is-plain-object "^2.0.4"
2527+
2528+is-extglob@^2.1.0, is-extglob@^2.1.1:
2529+ version "2.1.1"
2530+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
2531+ integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
2532+
2533+is-finite@^1.0.0:
2534+ version "1.1.0"
2535+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3"
2536+ integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==
2537+
2538+is-fullwidth-code-point@^1.0.0:
2539+ version "1.0.0"
2540+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
2541+ integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
2542+ dependencies:
2543+ number-is-nan "^1.0.0"
2544+
2545+is-glob@^3.1.0:
2546+ version "3.1.0"
2547+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
2548+ integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
2549+ dependencies:
2550+ is-extglob "^2.1.0"
2551+
2552+is-glob@^4.0.0, is-glob@^4.0.1:
2553+ version "4.0.1"
2554+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
2555+ integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
2556+ dependencies:
2557+ is-extglob "^2.1.1"
2558+
2559+is-negated-glob@^1.0.0:
2560+ version "1.0.0"
2561+ resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2"
2562+ integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=
2563+
2564+is-number@^3.0.0:
2565+ version "3.0.0"
2566+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
2567+ integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
2568+ dependencies:
2569+ kind-of "^3.0.2"
2570+
2571+is-number@^4.0.0:
2572+ version "4.0.0"
2573+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
2574+ integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
2575+
2576+is-number@^7.0.0:
2577+ version "7.0.0"
2578+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
2579+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
2580+
2581+is-obj@^1.0.0:
2582+ version "1.0.1"
2583+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
2584+ integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
2585+
2586+is-obj@^2.0.0:
2587+ version "2.0.0"
2588+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
2589+ integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
2590+
2591+is-path-cwd@^2.2.0:
2592+ version "2.2.0"
2593+ resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
2594+ integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
2595+
2596+is-path-inside@^3.0.2:
2597+ version "3.0.3"
2598+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
2599+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
2600+
2601+is-plain-obj@^1.1.0:
2602+ version "1.1.0"
2603+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
2604+ integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
2605+
2606+is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
2607+ version "2.0.4"
2608+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
2609+ integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
2610+ dependencies:
2611+ isobject "^3.0.1"
2612+
2613+is-plain-object@^5.0.0:
2614+ version "5.0.0"
2615+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
2616+ integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
2617+
2618+is-relative@^1.0.0:
2619+ version "1.0.0"
2620+ resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
2621+ integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==
2622+ dependencies:
2623+ is-unc-path "^1.0.0"
2624+
2625+is-text-path@^1.0.1:
2626+ version "1.0.1"
2627+ resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e"
2628+ integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=
2629+ dependencies:
2630+ text-extensions "^1.0.0"
2631+
2632+is-typedarray@~1.0.0:
2633+ version "1.0.0"
2634+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
2635+ integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
2636+
2637+is-unc-path@^1.0.0:
2638+ version "1.0.0"
2639+ resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
2640+ integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==
2641+ dependencies:
2642+ unc-path-regex "^0.1.2"
2643+
2644+is-utf8@^0.2.0, is-utf8@^0.2.1:
2645+ version "0.2.1"
2646+ resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
2647+ integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
2648+
2649+is-valid-glob@^1.0.0:
2650+ version "1.0.0"
2651+ resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa"
2652+ integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=
2653+
2654+is-windows@^1.0.1, is-windows@^1.0.2:
2655+ version "1.0.2"
2656+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
2657+ integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
2658+
2659+isarray@1.0.0, isarray@~1.0.0:
2660+ version "1.0.0"
2661+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
2662+ integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
2663+
2664+isexe@^2.0.0:
2665+ version "2.0.0"
2666+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
2667+ integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
2668+
2669+isobject@^2.0.0:
2670+ version "2.1.0"
2671+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
2672+ integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
2673+ dependencies:
2674+ isarray "1.0.0"
2675+
2676+isobject@^3.0.0, isobject@^3.0.1:
2677+ version "3.0.1"
2678+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
2679+ integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
2680+
2681+isstream@~0.1.2:
2682+ version "0.1.2"
2683+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
2684+ integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
2685+
2686+jasmine-core@~3.8.0:
2687+ version "3.8.0"
2688+ resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.8.0.tgz#815399aae5aa5d9beeb1262805f981b99ffc9bf0"
2689+ integrity sha512-zl0nZWDrmbCiKns0NcjkFGYkVTGCPUgoHypTaj+G2AzaWus7QGoXARSlYsSle2VRpSdfJmM+hzmFKzQNhF2kHg==
2690+
2691+jasmine-terminal-reporter@^1.0.3:
2692+ version "1.0.3"
2693+ resolved "https://registry.yarnpkg.com/jasmine-terminal-reporter/-/jasmine-terminal-reporter-1.0.3.tgz#896f1ec8fdf4bf6aecdd41c503eda7347f61526b"
2694+ integrity sha1-iW8eyP30v2rs3UHFA+2nNH9hUms=
2695+ dependencies:
2696+ indent-string "^2.1.0"
2697+ pluralize "^1.2.1"
2698+
2699+jasmine@^3.1.0, jasmine@^3.6.1:
2700+ version "3.8.0"
2701+ resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.8.0.tgz#4497bc797eede7ca9de18179aedd4cf50245d8dc"
2702+ integrity sha512-kdQ3SfcNpMbbMdgJPLyFe9IksixdnrgYaCJapP9sS0aLgdWdIZADNXEr+11Zafxm1VDfRSC5ZL4fzXT0bexzXw==
2703+ dependencies:
2704+ glob "^7.1.6"
2705+ jasmine-core "~3.8.0"
2706+
2707+js-tokens@^4.0.0:
2708+ version "4.0.0"
2709+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
2710+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
2711+
2712+js-yaml@^3.13.1:
2713+ version "3.14.1"
2714+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
2715+ integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
2716+ dependencies:
2717+ argparse "^1.0.7"
2718+ esprima "^4.0.0"
2719+
2720+js-yaml@^4.0.0, js-yaml@^4.1.0:
2721+ version "4.1.0"
2722+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
2723+ integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
2724+ dependencies:
2725+ argparse "^2.0.1"
2726+
2727+jsbn@~0.1.0:
2728+ version "0.1.1"
2729+ resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
2730+ integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
2731+
2732+json-parse-better-errors@^1.0.1:
2733+ version "1.0.2"
2734+ resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
2735+ integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
2736+
2737+json-parse-even-better-errors@^2.3.0:
2738+ version "2.3.1"
2739+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
2740+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
2741+
2742+json-schema-diff@^0.16.0:
2743+ version "0.16.0"
2744+ resolved "https://registry.yarnpkg.com/json-schema-diff/-/json-schema-diff-0.16.0.tgz#ee703abe7d23983244c0cfd7f11daca60fd31454"
2745+ integrity sha512-jNpsidxig8D9WdK1O4hMkcqtnNiGgtk9gxKQfhGGJT9EhOVKLR6YZX+Ft81nz1Rp5FXS4XNwgtGUMUICx3cBYA==
2746+ dependencies:
2747+ ajv "^6.12.3"
2748+ commander "^5.0.0"
2749+ json-schema-ref-parser "^9.0.6"
2750+ json-schema-spec-types "^0.1.2"
2751+ lodash "^4.17.19"
2752+ verror "^1.10.0"
2753+
2754+json-schema-ref-parser@^9.0.6:
2755+ version "9.0.9"
2756+ resolved "https://registry.yarnpkg.com/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#66ea538e7450b12af342fa3d5b8458bc1e1e013f"
2757+ integrity sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==
2758+ dependencies:
2759+ "@apidevtools/json-schema-ref-parser" "9.0.9"
2760+
2761+json-schema-spec-types@^0.1.2:
2762+ version "0.1.2"
2763+ resolved "https://registry.yarnpkg.com/json-schema-spec-types/-/json-schema-spec-types-0.1.2.tgz#c4dac1c8b70c99f19b24afedb210e1dfc48665e2"
2764+ integrity sha512-MDl8fA8ONckmQOm2+eXKJaFJNvxk7eGin+XFofNjS3q3PRKSoEvgMVb0ehOpCAYkUiLoMiqdU7obV7AmzAmyLw==
2765+
2766+json-schema-traverse@^0.4.1:
2767+ version "0.4.1"
2768+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
2769+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
2770+
2771+json-schema@0.2.3:
2772+ version "0.2.3"
2773+ resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
2774+ integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
2775+
2776+json-stable-stringify-without-jsonify@^1.0.1:
2777+ version "1.0.1"
2778+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
2779+ integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
2780+
2781+json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
2782+ version "5.0.1"
2783+ resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
2784+ integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
2785+
2786+jsonparse@^1.2.0:
2787+ version "1.3.1"
2788+ resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
2789+ integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
2790+
2791+jsonpointer@^4.1.0:
2792+ version "4.1.0"
2793+ resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.1.0.tgz#501fb89986a2389765ba09e6053299ceb4f2c2cc"
2794+ integrity sha512-CXcRvMyTlnR53xMcKnuMzfCA5i/nfblTnnr74CZb6C4vG39eu6w51t7nKmU5MfLfbTgGItliNyjO/ciNPDqClg==
2795+
2796+jsprim@^1.2.2:
2797+ version "1.4.1"
2798+ resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
2799+ integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
2800+ dependencies:
2801+ assert-plus "1.0.0"
2802+ extsprintf "1.3.0"
2803+ json-schema "0.2.3"
2804+ verror "1.10.0"
2805+
2806+just-debounce@^1.0.0:
2807+ version "1.1.0"
2808+ resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.1.0.tgz#2f81a3ad4121a76bc7cb45dbf704c0d76a8e5ddf"
2809+ integrity sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==
2810+
2811+kind-of@^1.1.0:
2812+ version "1.1.0"
2813+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44"
2814+ integrity sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=
2815+
2816+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
2817+ version "3.2.2"
2818+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
2819+ integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
2820+ dependencies:
2821+ is-buffer "^1.1.5"
2822+
2823+kind-of@^4.0.0:
2824+ version "4.0.0"
2825+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
2826+ integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
2827+ dependencies:
2828+ is-buffer "^1.1.5"
2829+
2830+kind-of@^5.0.0, kind-of@^5.0.2:
2831+ version "5.1.0"
2832+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
2833+ integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
2834+
2835+kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
2836+ version "6.0.3"
2837+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
2838+ integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
2839+
2840+last-run@^1.1.0:
2841+ version "1.1.1"
2842+ resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b"
2843+ integrity sha1-RblpQsF7HHnHchmCWbqUO+v4yls=
2844+ dependencies:
2845+ default-resolution "^2.0.0"
2846+ es6-weak-map "^2.0.1"
2847+
2848+lazystream@^1.0.0:
2849+ version "1.0.0"
2850+ resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
2851+ integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
2852+ dependencies:
2853+ readable-stream "^2.0.5"
2854+
2855+lcid@^1.0.0:
2856+ version "1.0.0"
2857+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
2858+ integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
2859+ dependencies:
2860+ invert-kv "^1.0.0"
2861+
2862+lead@^1.0.0:
2863+ version "1.0.0"
2864+ resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42"
2865+ integrity sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=
2866+ dependencies:
2867+ flush-write-stream "^1.0.2"
2868+
2869+liftoff@^3.1.0:
2870+ version "3.1.0"
2871+ resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3"
2872+ integrity sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==
2873+ dependencies:
2874+ extend "^3.0.0"
2875+ findup-sync "^3.0.0"
2876+ fined "^1.0.1"
2877+ flagged-respawn "^1.0.0"
2878+ is-plain-object "^2.0.4"
2879+ object.map "^1.0.0"
2880+ rechoir "^0.6.2"
2881+ resolve "^1.1.7"
2882+
2883+lines-and-columns@^1.1.6:
2884+ version "1.1.6"
2885+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
2886+ integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
2887+
2888+load-json-file@^1.0.0:
2889+ version "1.1.0"
2890+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
2891+ integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
2892+ dependencies:
2893+ graceful-fs "^4.1.2"
2894+ parse-json "^2.2.0"
2895+ pify "^2.0.0"
2896+ pinkie-promise "^2.0.0"
2897+ strip-bom "^2.0.0"
2898+
2899+load-json-file@^4.0.0:
2900+ version "4.0.0"
2901+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
2902+ integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
2903+ dependencies:
2904+ graceful-fs "^4.1.2"
2905+ parse-json "^4.0.0"
2906+ pify "^3.0.0"
2907+ strip-bom "^3.0.0"
2908+
2909+locate-path@^2.0.0:
2910+ version "2.0.0"
2911+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
2912+ integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
2913+ dependencies:
2914+ p-locate "^2.0.0"
2915+ path-exists "^3.0.0"
2916+
2917+locate-path@^5.0.0:
2918+ version "5.0.0"
2919+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
2920+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
2921+ dependencies:
2922+ p-locate "^4.1.0"
2923+
2924+lodash._reinterpolate@^3.0.0:
2925+ version "3.0.0"
2926+ resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
2927+ integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
2928+
2929+lodash.get@^4.4.2:
2930+ version "4.4.2"
2931+ resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
2932+ integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
2933+
2934+lodash.isequal@^4.5.0:
2935+ version "4.5.0"
2936+ resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
2937+ integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
2938+
2939+lodash.ismatch@^4.4.0:
2940+ version "4.4.0"
2941+ resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37"
2942+ integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=
2943+
2944+lodash.template@^4.4.0:
2945+ version "4.5.0"
2946+ resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
2947+ integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==
2948+ dependencies:
2949+ lodash._reinterpolate "^3.0.0"
2950+ lodash.templatesettings "^4.0.0"
2951+
2952+lodash.templatesettings@^4.0.0:
2953+ version "4.2.0"
2954+ resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33"
2955+ integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==
2956+ dependencies:
2957+ lodash._reinterpolate "^3.0.0"
2958+
2959+lodash@4.17.15:
2960+ version "4.17.15"
2961+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
2962+ integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
2963+
2964+lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.2.1:
2965+ version "4.17.21"
2966+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
2967+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
2968+
2969+loud-rejection@^1.0.0:
2970+ version "1.6.0"
2971+ resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
2972+ integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
2973+ dependencies:
2974+ currently-unhandled "^0.4.1"
2975+ signal-exit "^3.0.0"
2976+
2977+lru-cache@^6.0.0:
2978+ version "6.0.0"
2979+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
2980+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
2981+ dependencies:
2982+ yallist "^4.0.0"
2983+
2984+make-iterator@^1.0.0:
2985+ version "1.0.1"
2986+ resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6"
2987+ integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==
2988+ dependencies:
2989+ kind-of "^6.0.2"
2990+
2991+map-cache@^0.2.0, map-cache@^0.2.2:
2992+ version "0.2.2"
2993+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
2994+ integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
2995+
2996+map-obj@^1.0.0:
2997+ version "1.0.1"
2998+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
2999+ integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
3000+
3001+map-obj@^2.0.0:
3002+ version "2.0.0"
3003+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9"
3004+ integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk=
3005+
3006+map-obj@^4.0.0:
3007+ version "4.2.1"
3008+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7"
3009+ integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==
3010+
3011+map-stream@~0.0.7:
3012+ version "0.0.7"
3013+ resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8"
3014+ integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=
3015+
3016+map-visit@^1.0.0:
3017+ version "1.0.0"
3018+ resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
3019+ integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
3020+ dependencies:
3021+ object-visit "^1.0.0"
3022+
3023+matchdep@^2.0.0:
3024+ version "2.0.0"
3025+ resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e"
3026+ integrity sha1-xvNINKDY28OzfCfui7yyfHd1WC4=
3027+ dependencies:
3028+ findup-sync "^2.0.0"
3029+ micromatch "^3.0.4"
3030+ resolve "^1.4.0"
3031+ stack-trace "0.0.10"
3032+
3033+media-typer@0.3.0:
3034+ version "0.3.0"
3035+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
3036+ integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
3037+
3038+meow@5.0.0:
3039+ version "5.0.0"
3040+ resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4"
3041+ integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==
3042+ dependencies:
3043+ camelcase-keys "^4.0.0"
3044+ decamelize-keys "^1.0.0"
3045+ loud-rejection "^1.0.0"
3046+ minimist-options "^3.0.1"
3047+ normalize-package-data "^2.3.4"
3048+ read-pkg-up "^3.0.0"
3049+ redent "^2.0.0"
3050+ trim-newlines "^2.0.0"
3051+ yargs-parser "^10.0.0"
3052+
3053+meow@^7.0.0:
3054+ version "7.1.1"
3055+ resolved "https://registry.yarnpkg.com/meow/-/meow-7.1.1.tgz#7c01595e3d337fcb0ec4e8eed1666ea95903d306"
3056+ integrity sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==
3057+ dependencies:
3058+ "@types/minimist" "^1.2.0"
3059+ camelcase-keys "^6.2.2"
3060+ decamelize-keys "^1.1.0"
3061+ hard-rejection "^2.1.0"
3062+ minimist-options "4.1.0"
3063+ normalize-package-data "^2.5.0"
3064+ read-pkg-up "^7.0.1"
3065+ redent "^3.0.0"
3066+ trim-newlines "^3.0.0"
3067+ type-fest "^0.13.1"
3068+ yargs-parser "^18.1.3"
3069+
3070+meow@^8.0.0:
3071+ version "8.1.2"
3072+ resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897"
3073+ integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==
3074+ dependencies:
3075+ "@types/minimist" "^1.2.0"
3076+ camelcase-keys "^6.2.2"
3077+ decamelize-keys "^1.1.0"
3078+ hard-rejection "^2.1.0"
3079+ minimist-options "4.1.0"
3080+ normalize-package-data "^3.0.0"
3081+ read-pkg-up "^7.0.1"
3082+ redent "^3.0.0"
3083+ trim-newlines "^3.0.0"
3084+ type-fest "^0.18.0"
3085+ yargs-parser "^20.2.3"
3086+
3087+merge-descriptors@1.0.1:
3088+ version "1.0.1"
3089+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
3090+ integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
3091+
3092+merge2@^1.3.0:
3093+ version "1.4.1"
3094+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
3095+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
3096+
3097+methods@~1.1.2:
3098+ version "1.1.2"
3099+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
3100+ integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
3101+
3102+micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
3103+ version "3.1.10"
3104+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
3105+ integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
3106+ dependencies:
3107+ arr-diff "^4.0.0"
3108+ array-unique "^0.3.2"
3109+ braces "^2.3.1"
3110+ define-property "^2.0.2"
3111+ extend-shallow "^3.0.2"
3112+ extglob "^2.0.4"
3113+ fragment-cache "^0.2.1"
3114+ kind-of "^6.0.2"
3115+ nanomatch "^1.2.9"
3116+ object.pick "^1.3.0"
3117+ regex-not "^1.0.0"
3118+ snapdragon "^0.8.1"
3119+ to-regex "^3.0.2"
3120+
3121+micromatch@^4.0.4:
3122+ version "4.0.4"
3123+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
3124+ integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
3125+ dependencies:
3126+ braces "^3.0.1"
3127+ picomatch "^2.2.3"
3128+
3129+mime-db@1.48.0:
3130+ version "1.48.0"
3131+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d"
3132+ integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==
3133+
3134+mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
3135+ version "2.1.31"
3136+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b"
3137+ integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==
3138+ dependencies:
3139+ mime-db "1.48.0"
3140+
3141+mime@1.6.0:
3142+ version "1.6.0"
3143+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
3144+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
3145+
3146+min-indent@^1.0.0:
3147+ version "1.0.1"
3148+ resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
3149+ integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
3150+
3151+minimatch@^3.0.4:
3152+ version "3.0.4"
3153+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
3154+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
3155+ dependencies:
3156+ brace-expansion "^1.1.7"
3157+
3158+minimist-options@4.1.0:
3159+ version "4.1.0"
3160+ resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
3161+ integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
3162+ dependencies:
3163+ arrify "^1.0.1"
3164+ is-plain-obj "^1.1.0"
3165+ kind-of "^6.0.3"
3166+
3167+minimist-options@^3.0.1:
3168+ version "3.0.2"
3169+ resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954"
3170+ integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==
3171+ dependencies:
3172+ arrify "^1.0.1"
3173+ is-plain-obj "^1.1.0"
3174+
3175+minimist@^1.2.5:
3176+ version "1.2.5"
3177+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
3178+ integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
3179+
3180+mixin-deep@^1.2.0:
3181+ version "1.3.2"
3182+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
3183+ integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
3184+ dependencies:
3185+ for-in "^1.0.2"
3186+ is-extendable "^1.0.1"
3187+
3188+mkdirp@^0.5.1, mkdirp@^0.5.3:
3189+ version "0.5.5"
3190+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
3191+ integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
3192+ dependencies:
3193+ minimist "^1.2.5"
3194+
3195+modify-values@^1.0.0:
3196+ version "1.0.1"
3197+ resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
3198+ integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
3199+
3200+ms@2.0.0:
3201+ version "2.0.0"
3202+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
3203+ integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
3204+
3205+ms@2.1.1:
3206+ version "2.1.1"
3207+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
3208+ integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
3209+
3210+multimatch@^4.0.0:
3211+ version "4.0.0"
3212+ resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3"
3213+ integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==
3214+ dependencies:
3215+ "@types/minimatch" "^3.0.3"
3216+ array-differ "^3.0.0"
3217+ array-union "^2.1.0"
3218+ arrify "^2.0.1"
3219+ minimatch "^3.0.4"
3220+
3221+mute-stdout@^1.0.0:
3222+ version "1.0.1"
3223+ resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331"
3224+ integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==
3225+
3226+nan@^2.12.1:
3227+ version "2.14.2"
3228+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
3229+ integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
3230+
3231+nanomatch@^1.2.9:
3232+ version "1.2.13"
3233+ resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
3234+ integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
3235+ dependencies:
3236+ arr-diff "^4.0.0"
3237+ array-unique "^0.3.2"
3238+ define-property "^2.0.2"
3239+ extend-shallow "^3.0.2"
3240+ fragment-cache "^0.2.1"
3241+ is-windows "^1.0.2"
3242+ kind-of "^6.0.2"
3243+ object.pick "^1.3.0"
3244+ regex-not "^1.0.0"
3245+ snapdragon "^0.8.1"
3246+ to-regex "^3.0.1"
3247+
3248+negotiator@0.6.2:
3249+ version "0.6.2"
3250+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
3251+ integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
3252+
3253+neo-async@^2.6.0:
3254+ version "2.6.2"
3255+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
3256+ integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
3257+
3258+next-tick@~1.0.0:
3259+ version "1.0.0"
3260+ resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
3261+ integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
3262+
3263+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
3264+ version "2.5.0"
3265+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
3266+ integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
3267+ dependencies:
3268+ hosted-git-info "^2.1.4"
3269+ resolve "^1.10.0"
3270+ semver "2 || 3 || 4 || 5"
3271+ validate-npm-package-license "^3.0.1"
3272+
3273+normalize-package-data@^3.0.0:
3274+ version "3.0.2"
3275+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.2.tgz#cae5c410ae2434f9a6c1baa65d5bc3b9366c8699"
3276+ integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==
3277+ dependencies:
3278+ hosted-git-info "^4.0.1"
3279+ resolve "^1.20.0"
3280+ semver "^7.3.4"
3281+ validate-npm-package-license "^3.0.1"
3282+
3283+normalize-path@^2.1.1:
3284+ version "2.1.1"
3285+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
3286+ integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
3287+ dependencies:
3288+ remove-trailing-separator "^1.0.1"
3289+
3290+normalize-path@^3.0.0:
3291+ version "3.0.0"
3292+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
3293+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
3294+
3295+now-and-later@^2.0.0:
3296+ version "2.0.1"
3297+ resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.1.tgz#8e579c8685764a7cc02cb680380e94f43ccb1f7c"
3298+ integrity sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==
3299+ dependencies:
3300+ once "^1.3.2"
3301+
3302+number-is-nan@^1.0.0:
3303+ version "1.0.1"
3304+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
3305+ integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
3306+
3307+oauth-sign@~0.9.0:
3308+ version "0.9.0"
3309+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
3310+ integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
3311+
3312+object-assign@^4.0.1:
3313+ version "4.1.1"
3314+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
3315+ integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
3316+
3317+object-copy@^0.1.0:
3318+ version "0.1.0"
3319+ resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
3320+ integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
3321+ dependencies:
3322+ copy-descriptor "^0.1.0"
3323+ define-property "^0.2.5"
3324+ kind-of "^3.0.3"
3325+
3326+object-keys@^1.0.12, object-keys@^1.1.1:
3327+ version "1.1.1"
3328+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
3329+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
3330+
3331+object-visit@^1.0.0:
3332+ version "1.0.1"
3333+ resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
3334+ integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
3335+ dependencies:
3336+ isobject "^3.0.0"
3337+
3338+object.assign@^4.0.4, object.assign@^4.1.0:
3339+ version "4.1.2"
3340+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
3341+ integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
3342+ dependencies:
3343+ call-bind "^1.0.0"
3344+ define-properties "^1.1.3"
3345+ has-symbols "^1.0.1"
3346+ object-keys "^1.1.1"
3347+
3348+object.defaults@^1.0.0, object.defaults@^1.1.0:
3349+ version "1.1.0"
3350+ resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf"
3351+ integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=
3352+ dependencies:
3353+ array-each "^1.0.1"
3354+ array-slice "^1.0.0"
3355+ for-own "^1.0.0"
3356+ isobject "^3.0.0"
3357+
3358+object.map@^1.0.0:
3359+ version "1.0.1"
3360+ resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37"
3361+ integrity sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=
3362+ dependencies:
3363+ for-own "^1.0.0"
3364+ make-iterator "^1.0.0"
3365+
3366+object.pick@^1.2.0, object.pick@^1.3.0:
3367+ version "1.3.0"
3368+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
3369+ integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
3370+ dependencies:
3371+ isobject "^3.0.1"
3372+
3373+object.reduce@^1.0.0:
3374+ version "1.0.1"
3375+ resolved "https://registry.yarnpkg.com/object.reduce/-/object.reduce-1.0.1.tgz#6fe348f2ac7fa0f95ca621226599096825bb03ad"
3376+ integrity sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=
3377+ dependencies:
3378+ for-own "^1.0.0"
3379+ make-iterator "^1.0.0"
3380+
3381+on-finished@~2.3.0:
3382+ version "2.3.0"
3383+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
3384+ integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
3385+ dependencies:
3386+ ee-first "1.1.1"
3387+
3388+once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0:
3389+ version "1.4.0"
3390+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
3391+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
3392+ dependencies:
3393+ wrappy "1"
3394+
3395+openapi-types@^7.0.1:
3396+ version "7.2.3"
3397+ resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-7.2.3.tgz#83829911a3410a022f0e0cf2b0b2e67232ccf96e"
3398+ integrity sha512-olbaNxz12R27+mTyJ/ZAFEfUruauHH27AkeQHDHRq5AF0LdNkK1SSV7EourXQDK+4aX7dv2HtyirAGK06WMAsA==
3399+
3400+openapi3-ts@^2.0.0:
3401+ version "2.0.1"
3402+ resolved "https://registry.yarnpkg.com/openapi3-ts/-/openapi3-ts-2.0.1.tgz#b270aecea09e924f1886bc02a72608fca5a98d85"
3403+ integrity sha512-v6X3iwddhi276siej96jHGIqTx3wzVfMTmpGJEQDt7GPI7pI6sywItURLzpEci21SBRpPN/aOWSF5mVfFVNmcg==
3404+ dependencies:
3405+ yaml "^1.10.0"
3406+
3407+ordered-read-streams@^1.0.0:
3408+ version "1.0.1"
3409+ resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e"
3410+ integrity sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=
3411+ dependencies:
3412+ readable-stream "^2.0.1"
3413+
3414+os-locale@^1.4.0:
3415+ version "1.4.0"
3416+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
3417+ integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
3418+ dependencies:
3419+ lcid "^1.0.0"
3420+
3421+p-limit@^1.1.0:
3422+ version "1.3.0"
3423+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
3424+ integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
3425+ dependencies:
3426+ p-try "^1.0.0"
3427+
3428+p-limit@^2.2.0:
3429+ version "2.3.0"
3430+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
3431+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
3432+ dependencies:
3433+ p-try "^2.0.0"
3434+
3435+p-locate@^2.0.0:
3436+ version "2.0.0"
3437+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
3438+ integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
3439+ dependencies:
3440+ p-limit "^1.1.0"
3441+
3442+p-locate@^4.1.0:
3443+ version "4.1.0"
3444+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
3445+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
3446+ dependencies:
3447+ p-limit "^2.2.0"
3448+
3449+p-map@^4.0.0:
3450+ version "4.0.0"
3451+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
3452+ integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
3453+ dependencies:
3454+ aggregate-error "^3.0.0"
3455+
3456+p-try@^1.0.0:
3457+ version "1.0.0"
3458+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
3459+ integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
3460+
3461+p-try@^2.0.0:
3462+ version "2.2.0"
3463+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
3464+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
3465+
3466+parent-module@^1.0.0:
3467+ version "1.0.1"
3468+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
3469+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
3470+ dependencies:
3471+ callsites "^3.0.0"
3472+
3473+parse-filepath@^1.0.1:
3474+ version "1.0.2"
3475+ resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
3476+ integrity sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=
3477+ dependencies:
3478+ is-absolute "^1.0.0"
3479+ map-cache "^0.2.0"
3480+ path-root "^0.1.1"
3481+
3482+parse-json@^2.2.0:
3483+ version "2.2.0"
3484+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
3485+ integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
3486+ dependencies:
3487+ error-ex "^1.2.0"
3488+
3489+parse-json@^4.0.0:
3490+ version "4.0.0"
3491+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
3492+ integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
3493+ dependencies:
3494+ error-ex "^1.3.1"
3495+ json-parse-better-errors "^1.0.1"
3496+
3497+parse-json@^5.0.0:
3498+ version "5.2.0"
3499+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
3500+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
3501+ dependencies:
3502+ "@babel/code-frame" "^7.0.0"
3503+ error-ex "^1.3.1"
3504+ json-parse-even-better-errors "^2.3.0"
3505+ lines-and-columns "^1.1.6"
3506+
3507+parse-node-version@^1.0.0:
3508+ version "1.0.1"
3509+ resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
3510+ integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
3511+
3512+parse-passwd@^1.0.0:
3513+ version "1.0.0"
3514+ resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
3515+ integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
3516+
3517+parseurl@~1.3.3:
3518+ version "1.3.3"
3519+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
3520+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
3521+
3522+pascalcase@^0.1.1:
3523+ version "0.1.1"
3524+ resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
3525+ integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
3526+
3527+path-dirname@^1.0.0:
3528+ version "1.0.2"
3529+ resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
3530+ integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
3531+
3532+path-exists@^2.0.0:
3533+ version "2.1.0"
3534+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
3535+ integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
3536+ dependencies:
3537+ pinkie-promise "^2.0.0"
3538+
3539+path-exists@^3.0.0:
3540+ version "3.0.0"
3541+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
3542+ integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
3543+
3544+path-exists@^4.0.0:
3545+ version "4.0.0"
3546+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
3547+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
3548+
3549+path-is-absolute@^1.0.0:
3550+ version "1.0.1"
3551+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
3552+ integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
3553+
3554+path-parse@^1.0.6:
3555+ version "1.0.7"
3556+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
3557+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
3558+
3559+path-root-regex@^0.1.0:
3560+ version "0.1.2"
3561+ resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
3562+ integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=
3563+
3564+path-root@^0.1.1:
3565+ version "0.1.1"
3566+ resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
3567+ integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=
3568+ dependencies:
3569+ path-root-regex "^0.1.0"
3570+
3571+path-to-regexp@0.1.7:
3572+ version "0.1.7"
3573+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
3574+ integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
3575+
3576+path-type@^1.0.0:
3577+ version "1.1.0"
3578+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
3579+ integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
3580+ dependencies:
3581+ graceful-fs "^4.1.2"
3582+ pify "^2.0.0"
3583+ pinkie-promise "^2.0.0"
3584+
3585+path-type@^3.0.0:
3586+ version "3.0.0"
3587+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
3588+ integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==
3589+ dependencies:
3590+ pify "^3.0.0"
3591+
3592+path-type@^4.0.0:
3593+ version "4.0.0"
3594+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
3595+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
3596+
3597+performance-now@^2.1.0:
3598+ version "2.1.0"
3599+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
3600+ integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
3601+
3602+picomatch@^2.2.3:
3603+ version "2.3.0"
3604+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
3605+ integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
3606+
3607+pify@^2.0.0, pify@^2.3.0:
3608+ version "2.3.0"
3609+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
3610+ integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
3611+
3612+pify@^3.0.0:
3613+ version "3.0.0"
3614+ resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
3615+ integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
3616+
3617+pinkie-promise@^2.0.0:
3618+ version "2.0.1"
3619+ resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
3620+ integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
3621+ dependencies:
3622+ pinkie "^2.0.0"
3623+
3624+pinkie@^2.0.0:
3625+ version "2.0.4"
3626+ resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
3627+ integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
3628+
3629+plugin-error@1.0.1, plugin-error@^1.0.1:
3630+ version "1.0.1"
3631+ resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c"
3632+ integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==
3633+ dependencies:
3634+ ansi-colors "^1.0.1"
3635+ arr-diff "^4.0.0"
3636+ arr-union "^3.1.0"
3637+ extend-shallow "^3.0.2"
3638+
3639+plugin-error@^0.1.2:
3640+ version "0.1.2"
3641+ resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace"
3642+ integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=
3643+ dependencies:
3644+ ansi-cyan "^0.1.1"
3645+ ansi-red "^0.1.1"
3646+ arr-diff "^1.0.1"
3647+ arr-union "^2.0.1"
3648+ extend-shallow "^1.1.2"
3649+
3650+pluralize@^1.2.1:
3651+ version "1.2.1"
3652+ resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
3653+ integrity sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=
3654+
3655+posix-character-classes@^0.1.0:
3656+ version "0.1.1"
3657+ resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
3658+ integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
3659+
3660+pretty-hrtime@^1.0.0:
3661+ version "1.0.3"
3662+ resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
3663+ integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
3664+
3665+process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
3666+ version "2.0.1"
3667+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
3668+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
3669+
3670+proxy-addr@~2.0.5:
3671+ version "2.0.7"
3672+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
3673+ integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
3674+ dependencies:
3675+ forwarded "0.2.0"
3676+ ipaddr.js "1.9.1"
3677+
3678+psl@^1.1.28:
3679+ version "1.8.0"
3680+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
3681+ integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
3682+
3683+pump@^2.0.0:
3684+ version "2.0.1"
3685+ resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
3686+ integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
3687+ dependencies:
3688+ end-of-stream "^1.1.0"
3689+ once "^1.3.1"
3690+
3691+pumpify@^1.3.5:
3692+ version "1.5.1"
3693+ resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
3694+ integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
3695+ dependencies:
3696+ duplexify "^3.6.0"
3697+ inherits "^2.0.3"
3698+ pump "^2.0.0"
3699+
3700+punycode@^2.1.0, punycode@^2.1.1:
3701+ version "2.1.1"
3702+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
3703+ integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
3704+
3705+q@^1.5.1:
3706+ version "1.5.1"
3707+ resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
3708+ integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
3709+
3710+qs@6.7.0:
3711+ version "6.7.0"
3712+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
3713+ integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
3714+
3715+qs@~6.5.2:
3716+ version "6.5.2"
3717+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
3718+ integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
3719+
3720+queue-microtask@^1.2.2:
3721+ version "1.2.3"
3722+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
3723+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
3724+
3725+quick-lru@^1.0.0:
3726+ version "1.1.0"
3727+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
3728+ integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=
3729+
3730+quick-lru@^4.0.1:
3731+ version "4.0.1"
3732+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
3733+ integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
3734+
3735+range-parser@~1.2.1:
3736+ version "1.2.1"
3737+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
3738+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
3739+
3740+raw-body@2.4.0:
3741+ version "2.4.0"
3742+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
3743+ integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
3744+ dependencies:
3745+ bytes "3.1.0"
3746+ http-errors "1.7.2"
3747+ iconv-lite "0.4.24"
3748+ unpipe "1.0.0"
3749+
3750+read-pkg-up@^1.0.1:
3751+ version "1.0.1"
3752+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
3753+ integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
3754+ dependencies:
3755+ find-up "^1.0.0"
3756+ read-pkg "^1.0.0"
3757+
3758+read-pkg-up@^3.0.0:
3759+ version "3.0.0"
3760+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
3761+ integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=
3762+ dependencies:
3763+ find-up "^2.0.0"
3764+ read-pkg "^3.0.0"
3765+
3766+read-pkg-up@^7.0.1:
3767+ version "7.0.1"
3768+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
3769+ integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
3770+ dependencies:
3771+ find-up "^4.1.0"
3772+ read-pkg "^5.2.0"
3773+ type-fest "^0.8.1"
3774+
3775+read-pkg@^1.0.0:
3776+ version "1.1.0"
3777+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
3778+ integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
3779+ dependencies:
3780+ load-json-file "^1.0.0"
3781+ normalize-package-data "^2.3.2"
3782+ path-type "^1.0.0"
3783+
3784+read-pkg@^3.0.0:
3785+ version "3.0.0"
3786+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
3787+ integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=
3788+ dependencies:
3789+ load-json-file "^4.0.0"
3790+ normalize-package-data "^2.3.2"
3791+ path-type "^3.0.0"
3792+
3793+read-pkg@^5.2.0:
3794+ version "5.2.0"
3795+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
3796+ integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
3797+ dependencies:
3798+ "@types/normalize-package-data" "^2.4.0"
3799+ normalize-package-data "^2.5.0"
3800+ parse-json "^5.0.0"
3801+ type-fest "^0.6.0"
3802+
3803+"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6:
3804+ version "3.6.0"
3805+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
3806+ integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
3807+ dependencies:
3808+ inherits "^2.0.3"
3809+ string_decoder "^1.1.1"
3810+ util-deprecate "^1.0.1"
3811+
3812+readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
3813+ version "2.3.7"
3814+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
3815+ integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
3816+ dependencies:
3817+ core-util-is "~1.0.0"
3818+ inherits "~2.0.3"
3819+ isarray "~1.0.0"
3820+ process-nextick-args "~2.0.0"
3821+ safe-buffer "~5.1.1"
3822+ string_decoder "~1.1.1"
3823+ util-deprecate "~1.0.1"
3824+
3825+readdirp@^2.2.1:
3826+ version "2.2.1"
3827+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
3828+ integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
3829+ dependencies:
3830+ graceful-fs "^4.1.11"
3831+ micromatch "^3.1.10"
3832+ readable-stream "^2.0.2"
3833+
3834+rechoir@^0.6.2:
3835+ version "0.6.2"
3836+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
3837+ integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
3838+ dependencies:
3839+ resolve "^1.1.6"
3840+
3841+redent@^2.0.0:
3842+ version "2.0.0"
3843+ resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
3844+ integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=
3845+ dependencies:
3846+ indent-string "^3.0.0"
3847+ strip-indent "^2.0.0"
3848+
3849+redent@^3.0.0:
3850+ version "3.0.0"
3851+ resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
3852+ integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
3853+ dependencies:
3854+ indent-string "^4.0.0"
3855+ strip-indent "^3.0.0"
3856+
3857+regenerator-runtime@^0.10.5:
3858+ version "0.10.5"
3859+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
3860+ integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=
3861+
3862+regenerator-runtime@^0.11.0:
3863+ version "0.11.1"
3864+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
3865+ integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
3866+
3867+regex-not@^1.0.0, regex-not@^1.0.2:
3868+ version "1.0.2"
3869+ resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
3870+ integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
3871+ dependencies:
3872+ extend-shallow "^3.0.2"
3873+ safe-regex "^1.1.0"
3874+
3875+remove-bom-buffer@^3.0.0:
3876+ version "3.0.0"
3877+ resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53"
3878+ integrity sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==
3879+ dependencies:
3880+ is-buffer "^1.1.5"
3881+ is-utf8 "^0.2.1"
3882+
3883+remove-bom-stream@^1.2.0:
3884+ version "1.2.0"
3885+ resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523"
3886+ integrity sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=
3887+ dependencies:
3888+ remove-bom-buffer "^3.0.0"
3889+ safe-buffer "^5.1.0"
3890+ through2 "^2.0.3"
3891+
3892+remove-trailing-separator@^1.0.1, remove-trailing-separator@^1.1.0:
3893+ version "1.1.0"
3894+ resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
3895+ integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
3896+
3897+repeat-element@^1.1.2:
3898+ version "1.1.4"
3899+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9"
3900+ integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==
3901+
3902+repeat-string@^1.6.1:
3903+ version "1.6.1"
3904+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
3905+ integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
3906+
3907+repeating@^2.0.0:
3908+ version "2.0.1"
3909+ resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
3910+ integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
3911+ dependencies:
3912+ is-finite "^1.0.0"
3913+
3914+replace-ext@^1.0.0:
3915+ version "1.0.1"
3916+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a"
3917+ integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==
3918+
3919+replace-homedir@^1.0.0:
3920+ version "1.0.0"
3921+ resolved "https://registry.yarnpkg.com/replace-homedir/-/replace-homedir-1.0.0.tgz#e87f6d513b928dde808260c12be7fec6ff6e798c"
3922+ integrity sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=
3923+ dependencies:
3924+ homedir-polyfill "^1.0.1"
3925+ is-absolute "^1.0.0"
3926+ remove-trailing-separator "^1.1.0"
3927+
3928+request@^2.88.2:
3929+ version "2.88.2"
3930+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
3931+ integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
3932+ dependencies:
3933+ aws-sign2 "~0.7.0"
3934+ aws4 "^1.8.0"
3935+ caseless "~0.12.0"
3936+ combined-stream "~1.0.6"
3937+ extend "~3.0.2"
3938+ forever-agent "~0.6.1"
3939+ form-data "~2.3.2"
3940+ har-validator "~5.1.3"
3941+ http-signature "~1.2.0"
3942+ is-typedarray "~1.0.0"
3943+ isstream "~0.1.2"
3944+ json-stringify-safe "~5.0.1"
3945+ mime-types "~2.1.19"
3946+ oauth-sign "~0.9.0"
3947+ performance-now "^2.1.0"
3948+ qs "~6.5.2"
3949+ safe-buffer "^5.1.2"
3950+ tough-cookie "~2.5.0"
3951+ tunnel-agent "^0.6.0"
3952+ uuid "^3.3.2"
3953+
3954+require-dir@^1.0.0:
3955+ version "1.2.0"
3956+ resolved "https://registry.yarnpkg.com/require-dir/-/require-dir-1.2.0.tgz#0d443b75e96012d3ca749cf19f529a789ae74817"
3957+ integrity sha512-LY85DTSu+heYgDqq/mK+7zFHWkttVNRXC9NKcKGyuGLdlsfbjEPrIEYdCVrx6hqnJb+xSu3Lzaoo8VnmOhhjNA==
3958+
3959+require-directory@^2.1.1:
3960+ version "2.1.1"
3961+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
3962+ integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
3963+
3964+require-main-filename@^1.0.1:
3965+ version "1.0.1"
3966+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
3967+ integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
3968+
3969+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
3970+ version "1.0.1"
3971+ resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
3972+ integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
3973+ dependencies:
3974+ expand-tilde "^2.0.0"
3975+ global-modules "^1.0.0"
3976+
3977+resolve-from@5.0.0, resolve-from@^5.0.0:
3978+ version "5.0.0"
3979+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
3980+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
3981+
3982+resolve-from@^3.0.0:
3983+ version "3.0.0"
3984+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
3985+ integrity sha1-six699nWiBvItuZTM17rywoYh0g=
3986+
3987+resolve-from@^4.0.0:
3988+ version "4.0.0"
3989+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
3990+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
3991+
3992+resolve-global@1.0.0, resolve-global@^1.0.0:
3993+ version "1.0.0"
3994+ resolved "https://registry.yarnpkg.com/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255"
3995+ integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==
3996+ dependencies:
3997+ global-dirs "^0.1.1"
3998+
3999+resolve-options@^1.1.0:
4000+ version "1.1.0"
4001+ resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131"
4002+ integrity sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=
4003+ dependencies:
4004+ value-or-function "^3.0.0"
4005+
4006+resolve-url@^0.2.1:
4007+ version "0.2.1"
4008+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
4009+ integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
4010+
4011+resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.3.2, resolve@^1.4.0:
4012+ version "1.20.0"
4013+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
4014+ integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
4015+ dependencies:
4016+ is-core-module "^2.2.0"
4017+ path-parse "^1.0.6"
4018+
4019+ret@~0.1.10:
4020+ version "0.1.15"
4021+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
4022+ integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
4023+
4024+reusify@^1.0.4:
4025+ version "1.0.4"
4026+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
4027+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
4028+
4029+rimraf@^2.5.2, rimraf@^2.6.2:
4030+ version "2.7.1"
4031+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
4032+ integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
4033+ dependencies:
4034+ glob "^7.1.3"
4035+
4036+rimraf@^3.0.2:
4037+ version "3.0.2"
4038+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
4039+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
4040+ dependencies:
4041+ glob "^7.1.3"
4042+
4043+run-parallel@^1.1.9:
4044+ version "1.2.0"
4045+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
4046+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
4047+ dependencies:
4048+ queue-microtask "^1.2.2"
4049+
4050+safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
4051+ version "5.1.2"
4052+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
4053+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
4054+
4055+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
4056+ version "5.2.1"
4057+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
4058+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
4059+
4060+safe-regex@^1.1.0:
4061+ version "1.1.0"
4062+ resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
4063+ integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
4064+ dependencies:
4065+ ret "~0.1.10"
4066+
4067+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
4068+ version "2.1.2"
4069+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
4070+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
4071+
4072+semver-greatest-satisfied-range@^1.1.0:
4073+ version "1.1.0"
4074+ resolved "https://registry.yarnpkg.com/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz#13e8c2658ab9691cb0cd71093240280d36f77a5b"
4075+ integrity sha1-E+jCZYq5aRywzXEJMkAoDTb3els=
4076+ dependencies:
4077+ sver-compat "^1.5.0"
4078+
4079+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
4080+ version "5.7.1"
4081+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
4082+ integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
4083+
4084+semver@6.3.0, semver@^6.0.0:
4085+ version "6.3.0"
4086+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
4087+ integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
4088+
4089+semver@^7.3.4:
4090+ version "7.3.5"
4091+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
4092+ integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
4093+ dependencies:
4094+ lru-cache "^6.0.0"
4095+
4096+send@0.17.1:
4097+ version "0.17.1"
4098+ resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
4099+ integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
4100+ dependencies:
4101+ debug "2.6.9"
4102+ depd "~1.1.2"
4103+ destroy "~1.0.4"
4104+ encodeurl "~1.0.2"
4105+ escape-html "~1.0.3"
4106+ etag "~1.8.1"
4107+ fresh "0.5.2"
4108+ http-errors "~1.7.2"
4109+ mime "1.6.0"
4110+ ms "2.1.1"
4111+ on-finished "~2.3.0"
4112+ range-parser "~1.2.1"
4113+ statuses "~1.5.0"
4114+
4115+serve-static@1.14.1:
4116+ version "1.14.1"
4117+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
4118+ integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
4119+ dependencies:
4120+ encodeurl "~1.0.2"
4121+ escape-html "~1.0.3"
4122+ parseurl "~1.3.3"
4123+ send "0.17.1"
4124+
4125+set-blocking@^2.0.0:
4126+ version "2.0.0"
4127+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
4128+ integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
4129+
4130+set-value@^2.0.0, set-value@^2.0.1:
4131+ version "2.0.1"
4132+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
4133+ integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
4134+ dependencies:
4135+ extend-shallow "^2.0.1"
4136+ is-extendable "^0.1.1"
4137+ is-plain-object "^2.0.3"
4138+ split-string "^3.0.1"
4139+
4140+setprototypeof@1.1.1:
4141+ version "1.1.1"
4142+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
4143+ integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
4144+
4145+signal-exit@^3.0.0:
4146+ version "3.0.3"
4147+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
4148+ integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
4149+
4150+slash@^3.0.0:
4151+ version "3.0.0"
4152+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
4153+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
4154+
4155+snapdragon-node@^2.0.1:
4156+ version "2.1.1"
4157+ resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
4158+ integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
4159+ dependencies:
4160+ define-property "^1.0.0"
4161+ isobject "^3.0.0"
4162+ snapdragon-util "^3.0.1"
4163+
4164+snapdragon-util@^3.0.1:
4165+ version "3.0.1"
4166+ resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
4167+ integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
4168+ dependencies:
4169+ kind-of "^3.2.0"
4170+
4171+snapdragon@^0.8.1:
4172+ version "0.8.2"
4173+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
4174+ integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
4175+ dependencies:
4176+ base "^0.11.1"
4177+ debug "^2.2.0"
4178+ define-property "^0.2.5"
4179+ extend-shallow "^2.0.1"
4180+ map-cache "^0.2.2"
4181+ source-map "^0.5.6"
4182+ source-map-resolve "^0.5.0"
4183+ use "^3.1.0"
4184+
4185+source-map-resolve@^0.5.0:
4186+ version "0.5.3"
4187+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
4188+ integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
4189+ dependencies:
4190+ atob "^2.1.2"
4191+ decode-uri-component "^0.2.0"
4192+ resolve-url "^0.2.1"
4193+ source-map-url "^0.4.0"
4194+ urix "^0.1.0"
4195+
4196+source-map-url@^0.4.0:
4197+ version "0.4.1"
4198+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
4199+ integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
4200+
4201+source-map@^0.5.6:
4202+ version "0.5.7"
4203+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
4204+ integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
4205+
4206+source-map@^0.6.1:
4207+ version "0.6.1"
4208+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
4209+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
4210+
4211+source-map@^0.7.3:
4212+ version "0.7.3"
4213+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
4214+ integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
4215+
4216+sparkles@^1.0.0:
4217+ version "1.0.1"
4218+ resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c"
4219+ integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==
4220+
4221+spdx-correct@^3.0.0:
4222+ version "3.1.1"
4223+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
4224+ integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
4225+ dependencies:
4226+ spdx-expression-parse "^3.0.0"
4227+ spdx-license-ids "^3.0.0"
4228+
4229+spdx-exceptions@^2.1.0:
4230+ version "2.3.0"
4231+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
4232+ integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
4233+
4234+spdx-expression-parse@^3.0.0:
4235+ version "3.0.1"
4236+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
4237+ integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
4238+ dependencies:
4239+ spdx-exceptions "^2.1.0"
4240+ spdx-license-ids "^3.0.0"
4241+
4242+spdx-license-ids@^3.0.0:
4243+ version "3.0.9"
4244+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f"
4245+ integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==
4246+
4247+split-string@^3.0.1, split-string@^3.0.2:
4248+ version "3.1.0"
4249+ resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
4250+ integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
4251+ dependencies:
4252+ extend-shallow "^3.0.0"
4253+
4254+split2@^3.0.0:
4255+ version "3.2.2"
4256+ resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f"
4257+ integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==
4258+ dependencies:
4259+ readable-stream "^3.0.0"
4260+
4261+split@^1.0.0:
4262+ version "1.0.1"
4263+ resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
4264+ integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
4265+ dependencies:
4266+ through "2"
4267+
4268+sprintf-js@~1.0.2:
4269+ version "1.0.3"
4270+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
4271+ integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
4272+
4273+sshpk@^1.7.0:
4274+ version "1.16.1"
4275+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
4276+ integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
4277+ dependencies:
4278+ asn1 "~0.2.3"
4279+ assert-plus "^1.0.0"
4280+ bcrypt-pbkdf "^1.0.0"
4281+ dashdash "^1.12.0"
4282+ ecc-jsbn "~0.1.1"
4283+ getpass "^0.1.1"
4284+ jsbn "~0.1.0"
4285+ safer-buffer "^2.0.2"
4286+ tweetnacl "~0.14.0"
4287+
4288+stack-trace@0.0.10:
4289+ version "0.0.10"
4290+ resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
4291+ integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
4292+
4293+static-extend@^0.1.1:
4294+ version "0.1.2"
4295+ resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
4296+ integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
4297+ dependencies:
4298+ define-property "^0.2.5"
4299+ object-copy "^0.1.0"
4300+
4301+"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
4302+ version "1.5.0"
4303+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
4304+ integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
4305+
4306+stream-exhaust@^1.0.1:
4307+ version "1.0.2"
4308+ resolved "https://registry.yarnpkg.com/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d"
4309+ integrity sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==
4310+
4311+stream-shift@^1.0.0:
4312+ version "1.0.1"
4313+ resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
4314+ integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
4315+
4316+streamfilter@^3.0.0:
4317+ version "3.0.0"
4318+ resolved "https://registry.yarnpkg.com/streamfilter/-/streamfilter-3.0.0.tgz#8c61b08179a6c336c6efccc5df30861b7a9675e7"
4319+ integrity sha512-kvKNfXCmUyC8lAXSSHCIXBUlo/lhsLcCU/OmzACZYpRUdtKIH68xYhm/+HI15jFJYtNJGYtCgn2wmIiExY1VwA==
4320+ dependencies:
4321+ readable-stream "^3.0.6"
4322+
4323+string-width@^1.0.1, string-width@^1.0.2:
4324+ version "1.0.2"
4325+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
4326+ integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
4327+ dependencies:
4328+ code-point-at "^1.0.0"
4329+ is-fullwidth-code-point "^1.0.0"
4330+ strip-ansi "^3.0.0"
4331+
4332+string_decoder@^1.1.1:
4333+ version "1.3.0"
4334+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
4335+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
4336+ dependencies:
4337+ safe-buffer "~5.2.0"
4338+
4339+string_decoder@~1.1.1:
4340+ version "1.1.1"
4341+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
4342+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
4343+ dependencies:
4344+ safe-buffer "~5.1.0"
4345+
4346+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
4347+ version "3.0.1"
4348+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
4349+ integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
4350+ dependencies:
4351+ ansi-regex "^2.0.0"
4352+
4353+strip-bom-buf@^1.0.0:
4354+ version "1.0.0"
4355+ resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
4356+ integrity sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=
4357+ dependencies:
4358+ is-utf8 "^0.2.1"
4359+
4360+strip-bom-stream@^3.0.0:
4361+ version "3.0.0"
4362+ resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-3.0.0.tgz#956bcc5d84430f69256a90ed823765cd858e159c"
4363+ integrity sha1-lWvMXYRDD2klapDtgjdlzYWOFZw=
4364+ dependencies:
4365+ first-chunk-stream "^2.0.0"
4366+ strip-bom-buf "^1.0.0"
4367+
4368+strip-bom@^2.0.0:
4369+ version "2.0.0"
4370+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
4371+ integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
4372+ dependencies:
4373+ is-utf8 "^0.2.0"
4374+
4375+strip-bom@^3.0.0:
4376+ version "3.0.0"
4377+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
4378+ integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
4379+
4380+strip-indent@^2.0.0:
4381+ version "2.0.0"
4382+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
4383+ integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=
4384+
4385+strip-indent@^3.0.0:
4386+ version "3.0.0"
4387+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
4388+ integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
4389+ dependencies:
4390+ min-indent "^1.0.0"
4391+
4392+supports-color@^5.3.0:
4393+ version "5.5.0"
4394+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
4395+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
4396+ dependencies:
4397+ has-flag "^3.0.0"
4398+
4399+sver-compat@^1.5.0:
4400+ version "1.5.0"
4401+ resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8"
4402+ integrity sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=
4403+ dependencies:
4404+ es6-iterator "^2.0.1"
4405+ es6-symbol "^3.1.1"
4406+
4407+swagger-parser@^10.0.2:
4408+ version "10.0.2"
4409+ resolved "https://registry.yarnpkg.com/swagger-parser/-/swagger-parser-10.0.2.tgz#d7f18faa09c9c145e938977c9bd6c3435998b667"
4410+ integrity sha512-9jHkHM+QXyLGFLk1DkXBwV+4HyNm0Za3b8/zk/+mjr8jgOSiqm3FOTHBSDsBjtn9scdL+8eWcHdupp2NLM8tDw==
4411+ dependencies:
4412+ "@apidevtools/swagger-parser" "10.0.2"
4413+
4414+text-extensions@^1.0.0:
4415+ version "1.9.0"
4416+ resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26"
4417+ integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==
4418+
4419+through2-filter@^3.0.0:
4420+ version "3.0.0"
4421+ resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
4422+ integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
4423+ dependencies:
4424+ through2 "~2.0.0"
4425+ xtend "~4.0.0"
4426+
4427+through2@^2.0.0, through2@^2.0.3, through2@~2.0.0:
4428+ version "2.0.5"
4429+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
4430+ integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
4431+ dependencies:
4432+ readable-stream "~2.3.6"
4433+ xtend "~4.0.1"
4434+
4435+through2@^3.0.0:
4436+ version "3.0.2"
4437+ resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4"
4438+ integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==
4439+ dependencies:
4440+ inherits "^2.0.4"
4441+ readable-stream "2 || 3"
4442+
4443+through2@^4.0.0:
4444+ version "4.0.2"
4445+ resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764"
4446+ integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==
4447+ dependencies:
4448+ readable-stream "3"
4449+
4450+through@2, "through@>=2.2.7 <3", through@~2.3.8:
4451+ version "2.3.8"
4452+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
4453+ integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
4454+
4455+time-stamp@^1.0.0:
4456+ version "1.1.0"
4457+ resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
4458+ integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=
4459+
4460+to-absolute-glob@^2.0.0:
4461+ version "2.0.2"
4462+ resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b"
4463+ integrity sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=
4464+ dependencies:
4465+ is-absolute "^1.0.0"
4466+ is-negated-glob "^1.0.0"
4467+
4468+to-object-path@^0.3.0:
4469+ version "0.3.0"
4470+ resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
4471+ integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
4472+ dependencies:
4473+ kind-of "^3.0.2"
4474+
4475+to-regex-range@^2.1.0:
4476+ version "2.1.1"
4477+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
4478+ integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
4479+ dependencies:
4480+ is-number "^3.0.0"
4481+ repeat-string "^1.6.1"
4482+
4483+to-regex-range@^5.0.1:
4484+ version "5.0.1"
4485+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
4486+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
4487+ dependencies:
4488+ is-number "^7.0.0"
4489+
4490+to-regex@^3.0.1, to-regex@^3.0.2:
4491+ version "3.0.2"
4492+ resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
4493+ integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
4494+ dependencies:
4495+ define-property "^2.0.2"
4496+ extend-shallow "^3.0.2"
4497+ regex-not "^1.0.2"
4498+ safe-regex "^1.1.0"
4499+
4500+to-through@^2.0.0:
4501+ version "2.0.0"
4502+ resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6"
4503+ integrity sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=
4504+ dependencies:
4505+ through2 "^2.0.3"
4506+
4507+toidentifier@1.0.0:
4508+ version "1.0.0"
4509+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
4510+ integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
4511+
4512+tough-cookie@~2.5.0:
4513+ version "2.5.0"
4514+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
4515+ integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
4516+ dependencies:
4517+ psl "^1.1.28"
4518+ punycode "^2.1.1"
4519+
4520+trim-newlines@^2.0.0:
4521+ version "2.0.0"
4522+ resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20"
4523+ integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=
4524+
4525+trim-newlines@^3.0.0:
4526+ version "3.0.1"
4527+ resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
4528+ integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
4529+
4530+trim-off-newlines@^1.0.0:
4531+ version "1.0.1"
4532+ resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3"
4533+ integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM=
4534+
4535+tslib@^1.13.0, tslib@^1.8.1:
4536+ version "1.14.1"
4537+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
4538+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
4539+
4540+tslint@6.1.3:
4541+ version "6.1.3"
4542+ resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904"
4543+ integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==
4544+ dependencies:
4545+ "@babel/code-frame" "^7.0.0"
4546+ builtin-modules "^1.1.1"
4547+ chalk "^2.3.0"
4548+ commander "^2.12.1"
4549+ diff "^4.0.1"
4550+ glob "^7.1.1"
4551+ js-yaml "^3.13.1"
4552+ minimatch "^3.0.4"
4553+ mkdirp "^0.5.3"
4554+ resolve "^1.3.2"
4555+ semver "^5.3.0"
4556+ tslib "^1.13.0"
4557+ tsutils "^2.29.0"
4558+
4559+tsutils@^2.29.0:
4560+ version "2.29.0"
4561+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
4562+ integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
4563+ dependencies:
4564+ tslib "^1.8.1"
4565+
4566+tunnel-agent@^0.6.0:
4567+ version "0.6.0"
4568+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
4569+ integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
4570+ dependencies:
4571+ safe-buffer "^5.0.1"
4572+
4573+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
4574+ version "0.14.5"
4575+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
4576+ integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
4577+
4578+type-fest@^0.13.1:
4579+ version "0.13.1"
4580+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934"
4581+ integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
4582+
4583+type-fest@^0.18.0:
4584+ version "0.18.1"
4585+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
4586+ integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
4587+
4588+type-fest@^0.6.0:
4589+ version "0.6.0"
4590+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
4591+ integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
4592+
4593+type-fest@^0.8.1:
4594+ version "0.8.1"
4595+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
4596+ integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
4597+
4598+type-is@~1.6.17, type-is@~1.6.18:
4599+ version "1.6.18"
4600+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
4601+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
4602+ dependencies:
4603+ media-typer "0.3.0"
4604+ mime-types "~2.1.24"
4605+
4606+type@^1.0.1:
4607+ version "1.2.0"
4608+ resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
4609+ integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
4610+
4611+type@^2.0.0:
4612+ version "2.5.0"
4613+ resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d"
4614+ integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==
4615+
4616+typedarray@^0.0.6:
4617+ version "0.0.6"
4618+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
4619+ integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
4620+
4621+typescript@4.0.3:
4622+ version "4.0.3"
4623+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5"
4624+ integrity sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==
4625+
4626+uglify-js@^3.1.4:
4627+ version "3.13.10"
4628+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.10.tgz#a6bd0d28d38f592c3adb6b180ea6e07e1e540a8d"
4629+ integrity sha512-57H3ACYFXeo1IaZ1w02sfA71wI60MGco/IQFjOqK+WtKoprh7Go2/yvd2HPtoJILO2Or84ncLccI4xoHMTSbGg==
4630+
4631+unc-path-regex@^0.1.2:
4632+ version "0.1.2"
4633+ resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
4634+ integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo=
4635+
4636+undertaker-registry@^1.0.0:
4637+ version "1.0.1"
4638+ resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50"
4639+ integrity sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=
4640+
4641+undertaker@^1.2.1:
4642+ version "1.3.0"
4643+ resolved "https://registry.yarnpkg.com/undertaker/-/undertaker-1.3.0.tgz#363a6e541f27954d5791d6fa3c1d321666f86d18"
4644+ integrity sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==
4645+ dependencies:
4646+ arr-flatten "^1.0.1"
4647+ arr-map "^2.0.0"
4648+ bach "^1.0.0"
4649+ collection-map "^1.0.0"
4650+ es6-weak-map "^2.0.1"
4651+ fast-levenshtein "^1.0.0"
4652+ last-run "^1.1.0"
4653+ object.defaults "^1.0.0"
4654+ object.reduce "^1.0.0"
4655+ undertaker-registry "^1.0.0"
4656+
4657+union-value@^1.0.0:
4658+ version "1.0.1"
4659+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
4660+ integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
4661+ dependencies:
4662+ arr-union "^3.1.0"
4663+ get-value "^2.0.6"
4664+ is-extendable "^0.1.1"
4665+ set-value "^2.0.1"
4666+
4667+unique-stream@^2.0.2:
4668+ version "2.3.1"
4669+ resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
4670+ integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
4671+ dependencies:
4672+ json-stable-stringify-without-jsonify "^1.0.1"
4673+ through2-filter "^3.0.0"
4674+
4675+unpipe@1.0.0, unpipe@~1.0.0:
4676+ version "1.0.0"
4677+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
4678+ integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
4679+
4680+unset-value@^1.0.0:
4681+ version "1.0.0"
4682+ resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
4683+ integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
4684+ dependencies:
4685+ has-value "^0.3.1"
4686+ isobject "^3.0.0"
4687+
4688+upath@^1.1.1:
4689+ version "1.2.0"
4690+ resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
4691+ integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
4692+
4693+uri-js@^4.2.2:
4694+ version "4.4.1"
4695+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
4696+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
4697+ dependencies:
4698+ punycode "^2.1.0"
4699+
4700+urix@^0.1.0:
4701+ version "0.1.0"
4702+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
4703+ integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
4704+
4705+use@^3.1.0:
4706+ version "3.1.1"
4707+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
4708+ integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
4709+
4710+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
4711+ version "1.0.2"
4712+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
4713+ integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
4714+
4715+utils-merge@1.0.1:
4716+ version "1.0.1"
4717+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
4718+ integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
4719+
4720+uuid@^3.3.2:
4721+ version "3.4.0"
4722+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
4723+ integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
4724+
4725+v8flags@^3.2.0:
4726+ version "3.2.0"
4727+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656"
4728+ integrity sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==
4729+ dependencies:
4730+ homedir-polyfill "^1.0.1"
4731+
4732+validate-npm-package-license@^3.0.1:
4733+ version "3.0.4"
4734+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
4735+ integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
4736+ dependencies:
4737+ spdx-correct "^3.0.0"
4738+ spdx-expression-parse "^3.0.0"
4739+
4740+validator@^12.0.0:
4741+ version "12.2.0"
4742+ resolved "https://registry.yarnpkg.com/validator/-/validator-12.2.0.tgz#660d47e96267033fd070096c3b1a6f2db4380a0a"
4743+ integrity sha512-jJfE/DW6tIK1Ek8nCfNFqt8Wb3nzMoAbocBF6/Icgg1ZFSBpObdnwVY2jQj6qUqzhx5jc71fpvBWyLGO7Xl+nQ==
4744+
4745+value-or-function@^3.0.0:
4746+ version "3.0.0"
4747+ resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
4748+ integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=
4749+
4750+vary@~1.1.2:
4751+ version "1.1.2"
4752+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
4753+ integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
4754+
4755+verror@1.10.0, verror@^1.10.0:
4756+ version "1.10.0"
4757+ resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
4758+ integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
4759+ dependencies:
4760+ assert-plus "^1.0.0"
4761+ core-util-is "1.0.2"
4762+ extsprintf "^1.2.0"
4763+
4764+vinyl-fs@^3.0.0, vinyl-fs@^3.0.3:
4765+ version "3.0.3"
4766+ resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7"
4767+ integrity sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==
4768+ dependencies:
4769+ fs-mkdirp-stream "^1.0.0"
4770+ glob-stream "^6.1.0"
4771+ graceful-fs "^4.0.0"
4772+ is-valid-glob "^1.0.0"
4773+ lazystream "^1.0.0"
4774+ lead "^1.0.0"
4775+ object.assign "^4.0.4"
4776+ pumpify "^1.3.5"
4777+ readable-stream "^2.3.3"
4778+ remove-bom-buffer "^3.0.0"
4779+ remove-bom-stream "^1.2.0"
4780+ resolve-options "^1.1.0"
4781+ through2 "^2.0.0"
4782+ to-through "^2.0.0"
4783+ value-or-function "^3.0.0"
4784+ vinyl "^2.0.0"
4785+ vinyl-sourcemap "^1.1.0"
4786+
4787+vinyl-sourcemap@^1.1.0:
4788+ version "1.1.0"
4789+ resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16"
4790+ integrity sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=
4791+ dependencies:
4792+ append-buffer "^1.0.2"
4793+ convert-source-map "^1.5.0"
4794+ graceful-fs "^4.1.6"
4795+ normalize-path "^2.1.1"
4796+ now-and-later "^2.0.0"
4797+ remove-bom-buffer "^3.0.0"
4798+ vinyl "^2.0.0"
4799+
4800+vinyl@^2.0.0, vinyl@^2.0.1, vinyl@^2.1.0:
4801+ version "2.2.1"
4802+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974"
4803+ integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==
4804+ dependencies:
4805+ clone "^2.1.1"
4806+ clone-buffer "^1.0.0"
4807+ clone-stats "^1.0.0"
4808+ cloneable-readable "^1.0.0"
4809+ remove-trailing-separator "^1.0.1"
4810+ replace-ext "^1.0.0"
4811+
4812+which-module@^1.0.0:
4813+ version "1.0.0"
4814+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
4815+ integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
4816+
4817+which@^1.2.14:
4818+ version "1.3.1"
4819+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
4820+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
4821+ dependencies:
4822+ isexe "^2.0.0"
4823+
4824+wordwrap@^1.0.0:
4825+ version "1.0.0"
4826+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
4827+ integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
4828+
4829+wrap-ansi@^2.0.0:
4830+ version "2.1.0"
4831+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
4832+ integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
4833+ dependencies:
4834+ string-width "^1.0.1"
4835+ strip-ansi "^3.0.1"
4836+
4837+wrappy@1:
4838+ version "1.0.2"
4839+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
4840+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
4841+
4842+xtend@~4.0.0, xtend@~4.0.1:
4843+ version "4.0.2"
4844+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
4845+ integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
4846+
4847+y18n@^3.2.1:
4848+ version "3.2.2"
4849+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
4850+ integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
4851+
4852+yallist@^4.0.0:
4853+ version "4.0.0"
4854+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
4855+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
4856+
4857+yaml@^1.10.0:
4858+ version "1.10.2"
4859+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
4860+ integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
4861+
4862+yargs-parser@^10.0.0:
4863+ version "10.1.0"
4864+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
4865+ integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==
4866+ dependencies:
4867+ camelcase "^4.1.0"
4868+
4869+yargs-parser@^18.1.3:
4870+ version "18.1.3"
4871+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
4872+ integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
4873+ dependencies:
4874+ camelcase "^5.0.0"
4875+ decamelize "^1.2.0"
4876+
4877+yargs-parser@^20.2.3:
4878+ version "20.2.9"
4879+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
4880+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
4881+
4882+yargs-parser@^5.0.1:
4883+ version "5.0.1"
4884+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.1.tgz#7ede329c1d8cdbbe209bd25cdb990e9b1ebbb394"
4885+ integrity sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==
4886+ dependencies:
4887+ camelcase "^3.0.0"
4888+ object.assign "^4.1.0"
4889+
4890+yargs@^7.1.0:
4891+ version "7.1.2"
4892+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.2.tgz#63a0a5d42143879fdbb30370741374e0641d55db"
4893+ integrity sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==
4894+ dependencies:
4895+ camelcase "^3.0.0"
4896+ cliui "^3.2.0"
4897+ decamelize "^1.1.1"
4898+ get-caller-file "^1.0.1"
4899+ os-locale "^1.4.0"
4900+ read-pkg-up "^1.0.1"
4901+ require-directory "^2.1.1"
4902+ require-main-filename "^1.0.1"
4903+ set-blocking "^2.0.0"
4904+ string-width "^1.0.2"
4905+ which-module "^1.0.0"
4906+ y18n "^3.2.1"
4907+ yargs-parser "^5.0.1"
4908+
4909+z-schema@^4.2.3:
4910+ version "4.2.3"
4911+ resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-4.2.3.tgz#85f7eea7e6d4fe59a483462a98f511bd78fe9882"
4912+ integrity sha512-zkvK/9TC6p38IwcrbnT3ul9in1UX4cm1y/VZSs4GHKIiDCrlafc+YQBgQBUdDXLAoZHf2qvQ7gJJOo6yT1LH6A==
4913+ dependencies:
4914+ lodash.get "^4.4.2"
4915+ lodash.isequal "^4.5.0"
4916+ validator "^12.0.0"
4917+ optionalDependencies:
4918+ commander "^2.7.1"
benchmarks/default.nixnew file+181
@@ -0,0 +1,181 @@
1+{ sources ? import ./nix/sources.nix
2+, gomod2nix ? sources.gomod2nix
3+, haskellNix ? (import ../. {}).haskellNix
4+, pkgs ? import haskellNix.sources.nixpkgs-2105 (haskellNix.nixpkgsArgs // {
5+ overlays = haskellNix.nixpkgsArgs.overlays ++ [
6+ (self: super: {
7+ buildGoApplication = super.callPackage (gomod2nix + "/builder") { };
8+ })
9+ ];
10+ })
11+, compaRESThsPkgs ? (import ../. {}).hsPkgs
12+, npmNix ? import (sources.npmNix + "/npmPackages") { inherit pkgs; }
13+, mavenix ? import (sources.mavenix) { inherit pkgs; }
14+, bumpToken ? null
15+, bumpDocumentation ? null
16+}:
17+let
18+ typeable-comparest = compaRESThsPkgs.comparest.components.exes.comparest;
19+ typeable-comparest-exe = typeable-comparest + "/bin/comparest";
20+ typeable-comparest-differ = pkgs.writeScript "typeable-comparest-differ" ''
21+ #!${pkgs.stdenv.shell}
22+ set +e
23+ ${typeable-comparest-exe} -c $1 -s $2 -o $3/typeable.md
24+ exit 0
25+ '';
26+
27+ atlassian-openapi-diff = pkgs.mkYarnPackage {
28+ name = "openapi-diff";
29+ src = sources.atlassian-openapi-diff;
30+ yarnLock = ./atlassian/yarn.lock;
31+ patches = [ ./atlassian/addDist.patch ];
32+ postBuild = "yarn run gulp compileDist";
33+ };
34+ atlassian-openapi-diff-exe = atlassian-openapi-diff + "/bin/openapi-diff";
35+ atlassian-openapi-diff-differ = pkgs.writeScript "atlassian-openapi-diff-differ" ''
36+ #!${pkgs.stdenv.shell}
37+ set +e
38+ ${atlassian-openapi-diff-exe} $1 $2 >$3/atlassian.json 2>$3/atlassian.error.txt
39+ if [ ! -s $3/atlassian.error.txt ]; then
40+ rm $3/atlassian.error.txt
41+ fi
42+ exit 0
43+ '';
44+
45+ openapitools-openapi-diff = mavenix.buildMaven {
46+ maven = pkgs.maven;
47+ src = sources.openapitools-openapi-diff;
48+ doCheck = false;
49+ infoFile = ./openapitools/mavenix.lock;
50+ MAVEN_OPTS = "-Dgithook.plugin.skip=true";
51+ };
52+ openapitools-openapi-diff-exe =
53+ pkgs.runCommand "openapitools-openapi-diff"
54+ { buildInputs = [ pkgs.makeWrapper ]; }
55+ ''makeWrapper ${pkgs.jdk}/bin/java $out --add-flags "-jar ${openapitools-openapi-diff}/share/java/openapi-diff-cli-2.0.0-SNAPSHOT-all.jar"'';
56+ openapitools-openapi-diff-differ = pkgs.writeScript "openapitools-openapi-diff-differ" ''
57+ #!${pkgs.stdenv.shell}
58+ set +e
59+ ${openapitools-openapi-diff-exe} $1 $2 --off --markdown $3/openapitools.md 2>$3/openapitools.error.txt
60+ if [ ! -s $3/openapitools.error.txt ]; then
61+ rm $3/openapitools.error.txt
62+ fi
63+ exit 0
64+ '';
65+
66+ oasdiff = pkgs.pkgs.buildGoApplication {
67+ pname = "oasdiff";
68+ version = "0.1";
69+ src = sources.oasdiff;
70+ modules = ./oasdiff/gomod2nix.toml;
71+ };
72+ oasdiff-differ = pkgs.writeScript "oasdiff-differ" ''
73+ #!${pkgs.stdenv.shell}
74+ set +e
75+ ${oasdiff}/bin/oasdiff -base $1 -revision $2 -format text >$3/oasdiff.txt 2>$3/oasdiff.error.txt
76+ if [ ! -s $3/oasdiff.error.txt ]; then
77+ rm $3/oasdiff.error.txt
78+ fi
79+ exit 0
80+ '';
81+
82+ bump-differ = { bumpToken, bumpDocumentation }: pkgs.writeScript "bump-differ" ''
83+ #!${pkgs.stdenv.shell}
84+
85+ ${pkgs.httpie}/bin/https --ignore-stdin POST bump.sh/api/v1/versions definition=@$1 documentation=${bumpDocumentation} -a ${bumpToken}: >/dev/null
86+ id=$(${pkgs.httpie}/bin/https --ignore-stdin POST bump.sh/api/v1/versions definition=@$2 documentation=${bumpDocumentation} -a ${bumpToken}: | ${pkgs.jq}/bin/jq -r .id)
87+
88+ if [ -z "$id" ]
89+ then
90+ echo "Not changed" > $3/bump.txt
91+ else
92+ state=""
93+
94+ while [ "$state" != "deployed" ]
95+ do
96+ state=$(${pkgs.httpie}/bin/https --ignore-stdin GET bump.sh/api/v1/versions/$id -a ${bumpToken}: | ${pkgs.jq}/bin/jq -r .state)
97+ done
98+
99+ ${pkgs.httpie}/bin/https --ignore-stdin GET bump.sh/api/v1/versions/$id -a ${bumpToken}: | ${pkgs.jq}/bin/jq -r .diff_summary > $3/bump.txt
100+ fi
101+ '';
102+
103+ getInputs = with pkgs;
104+ dir: lib.flatten (lib.mapAttrsToList
105+ (name: type:
106+ if type == "directory" then
107+ let
108+ path = dir + "/${name}";
109+ contents = builtins.readDir path;
110+ in
111+ if contents."a.yaml" or null == "regular" && contents."b.yaml" or null == "regular"
112+ then path
113+ else getInputs path
114+ else [ ]
115+ )
116+ (builtins.readDir dir)
117+ );
118+
119+ runBenchmark = root: pkgs.runCommand "openapi-diff-benchmarks"
120+ {
121+ dirs = map
122+ (path: builtins.toJSON {
123+ relativePath = pkgs.lib.removePrefix (builtins.toString root) (builtins.toString path);
124+ a = path + "/a.yaml";
125+ b = path + "/b.yaml";
126+ })
127+ (getInputs root);
128+ differs = [
129+ typeable-comparest-differ
130+ atlassian-openapi-diff-differ
131+ openapitools-openapi-diff-differ
132+ oasdiff-differ
133+ ] ++ (
134+ if bumpToken == null || bumpDocumentation == null
135+ then builtins.trace "Warning: bumpToken or bumpDocumentation not provided. Skipping bump.sh benchmarks." [ ]
136+ else [ (bump-differ { inherit bumpToken bumpDocumentation; }) ]
137+ );
138+ }
139+ ''
140+ echo "Running compatibility checks:"
141+ for dir in $dirs
142+ do
143+ a=$(echo $dir | ${pkgs.jq}/bin/jq -r .a)
144+ b=$(echo $dir | ${pkgs.jq}/bin/jq -r .b)
145+ relativePath=$(echo $dir | ${pkgs.jq}/bin/jq -r .relativePath)
146+ echo "''\t$relativePath"
147+ output=$out$relativePath
148+ mkdir -p $output
149+ for differ in $differs
150+ do
151+ $differ $a $b $output
152+ done
153+ cp $a $output/a.yaml
154+ cp $b $output/b.yaml
155+ done
156+ '';
157+
158+ benchmarkReportTemplate = root:
159+ let
160+ tools = [
161+ "Typeable"
162+ "Atlassian"
163+ "OpenAPI Tools"
164+ "oasdiff"
165+ "Bump.sh"
166+ ];
167+ foo = with pkgs.lib.strings;
168+ concatMapStrings (x: "| " + x) ([ "" ] ++ tools) + "| \n" + concatMapStrings (_: "|---") ([ "" ] ++ tools) + "| \n" +
169+ concatMapStrings
170+ (path:
171+ let
172+ relativePath = pkgs.lib.removePrefix (builtins.toString root + "/") (builtins.toString path);
173+
174+ in
175+ "[${relativePath}](./${relativePath})${concatMapStrings (_: " | ✅❌") tools} \n")
176+ (getInputs root);
177+ in
178+ foo;
179+
180+in
181+runBenchmark ../test/golden/common
benchmarks/nix/sources.jsonnew file+92
@@ -0,0 +1,92 @@
1+{
2+ "atlassian-openapi-diff": {
3+ "branch": "master",
4+ "repo": "https://bitbucket.org/atlassian/openapi-diff.git",
5+ "rev": "68a0ebce1ec07f21b8e51a008321208c58eab1d6",
6+ "type": "git"
7+ },
8+ "gomod2nix": {
9+ "branch": "master",
10+ "description": "Convert applications using Go modules to Nix expressions",
11+ "homepage": null,
12+ "owner": "tweag",
13+ "repo": "gomod2nix",
14+ "rev": "c78d7b9f15a24eba95fbc228509f513c83709d8b",
15+ "sha256": "15qjp1g2pkkpr5b1mfjfiwl8kyfabi66hklk7apk7jh9sb2qqf85",
16+ "type": "tarball",
17+ "url": "https://github.com/tweag/gomod2nix/archive/c78d7b9f15a24eba95fbc228509f513c83709d8b.tar.gz",
18+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
19+ },
20+ "haskellNix": {
21+ "branch": "master",
22+ "description": "Alternative Haskell Infrastructure for Nixpkgs",
23+ "homepage": "https://input-output-hk.github.io/haskell.nix",
24+ "owner": "input-output-hk",
25+ "repo": "haskell.nix",
26+ "rev": "062a0317b6f1ec231864df49cb9c0fcc838e9c8a",
27+ "sha256": "0s5f8hnwqmz9anz175a53vay20f0185m92vyiga6yrslsar3vpin",
28+ "type": "tarball",
29+ "url": "https://github.com/input-output-hk/haskell.nix/archive/062a0317b6f1ec231864df49cb9c0fcc838e9c8a.tar.gz",
30+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
31+ },
32+ "mavenix": {
33+ "branch": "master",
34+ "description": "Deterministic Maven builds using Nix [maintainer=@icetan]",
35+ "homepage": "",
36+ "owner": "nix-community",
37+ "repo": "mavenix",
38+ "rev": "7416dbd2861520d44a4d6ecee9d94f89737412dc",
39+ "sha256": "0gkn29q63y2l700vravfl8nqjvd0zx7nvfcb3vj64fal3prh1l7y",
40+ "type": "tarball",
41+ "url": "https://github.com/nix-community/mavenix/archive/7416dbd2861520d44a4d6ecee9d94f89737412dc.tar.gz",
42+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
43+ },
44+ "niv": {
45+ "branch": "master",
46+ "description": "Easy dependency management for Nix projects",
47+ "homepage": "https://github.com/nmattia/niv",
48+ "owner": "nmattia",
49+ "repo": "niv",
50+ "rev": "e0ca65c81a2d7a4d82a189f1e23a48d59ad42070",
51+ "sha256": "1pq9nh1d8nn3xvbdny8fafzw87mj7gsmp6pxkdl65w2g18rmcmzx",
52+ "type": "tarball",
53+ "url": "https://github.com/nmattia/niv/archive/e0ca65c81a2d7a4d82a189f1e23a48d59ad42070.tar.gz",
54+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
55+ },
56+ "npmNix": {
57+ "branch": "master",
58+ "description": "Organize JavaScript packages with the Nix package manager.",
59+ "homepage": "https://medium.com/commitlog/the-internet-is-at-the-mercy-of-a-handful-of-people-73fac4bc5068",
60+ "owner": "ip1981",
61+ "repo": "npm.nix",
62+ "rev": "dd31fae2cfe7d4ed21fc9a9f226a81f382b86022",
63+ "sha256": "1a0aqawv6hslxn756yzb3f8ajf4gcms8b1abw2dwm0ck81jq2snc",
64+ "type": "tarball",
65+ "url": "https://github.com/ip1981/npm.nix/archive/dd31fae2cfe7d4ed21fc9a9f226a81f382b86022.tar.gz",
66+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
67+ },
68+ "oasdiff": {
69+ "branch": "main",
70+ "description": "A diff tool for OpenAPI Specification 3",
71+ "homepage": "",
72+ "owner": "tufin",
73+ "repo": "oasdiff",
74+ "rev": "8630d1b6eda369db321d0f7e153002c9bb7515b8",
75+ "sha256": "1p8lskhckgnwdy7vq28qvvls6j9flwliky8qwfhpzmsf43cxkjg6",
76+ "type": "tarball",
77+ "url": "https://github.com/tufin/oasdiff/archive/8630d1b6eda369db321d0f7e153002c9bb7515b8.tar.gz",
78+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
79+ },
80+ "openapitools-openapi-diff": {
81+ "branch": "master",
82+ "description": "Utility for comparing two OpenAPI specifications.",
83+ "homepage": null,
84+ "owner": "OpenAPITools",
85+ "repo": "openapi-diff",
86+ "rev": "1ae6fb0baa56cd7b61b50904f2c664cd86d64547",
87+ "sha256": "1aigv0hgzxfz3i3d0qxn7jp1hgkrlmhwcilpzza2y9j5qdfxkrvs",
88+ "type": "tarball",
89+ "url": "https://github.com/OpenAPITools/openapi-diff/archive/1ae6fb0baa56cd7b61b50904f2c664cd86d64547.tar.gz",
90+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
91+ }
92+}
benchmarks/nix/sources.nixnew file+171
@@ -0,0 +1,171 @@
1+# This file has been generated by Niv.
2+
3+let
4+
5+ #
6+ # The fetchers. fetch_<type> fetches specs of type <type>.
7+ #
8+
9+ fetch_file = pkgs: name: spec:
10+ let
11+ name' = sanitizeName name + "-src";
12+ in
13+ if spec.builtin or true then
14+ builtins_fetchurl { inherit (spec) url sha256; name = name'; }
15+ else
16+ pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
17+
18+ fetch_tarball = pkgs: name: spec:
19+ let
20+ name' = sanitizeName name + "-src";
21+ in
22+ if spec.builtin or true then
23+ builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
24+ else
25+ pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
26+
27+ fetch_git = name: spec:
28+ let
29+ ref =
30+ if spec ? ref then spec.ref else
31+ if spec ? branch then "refs/heads/${spec.branch}" else
32+ if spec ? tag then "refs/tags/${spec.tag}" else
33+ abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
34+ in
35+ builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
36+
37+ fetch_local = spec: spec.path;
38+
39+ fetch_builtin-tarball = name: throw
40+ ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
41+ $ niv modify ${name} -a type=tarball -a builtin=true'';
42+
43+ fetch_builtin-url = name: throw
44+ ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
45+ $ niv modify ${name} -a type=file -a builtin=true'';
46+
47+ #
48+ # Various helpers
49+ #
50+
51+ # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
52+ sanitizeName = name:
53+ (
54+ concatMapStrings (s: if builtins.isList s then "-" else s)
55+ (
56+ builtins.split "[^[:alnum:]+._?=-]+"
57+ ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
58+ )
59+ );
60+
61+ # The set of packages used when specs are fetched using non-builtins.
62+ mkPkgs = sources: system:
63+ let
64+ sourcesNixpkgs =
65+ import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
66+ hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
67+ hasThisAsNixpkgsPath = <nixpkgs> == ./.;
68+ in
69+ if builtins.hasAttr "nixpkgs" sources
70+ then sourcesNixpkgs
71+ else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
72+ import <nixpkgs> {}
73+ else
74+ abort
75+ ''
76+ Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
77+ add a package called "nixpkgs" to your sources.json.
78+ '';
79+
80+ # The actual fetching function.
81+ fetch = pkgs: name: spec:
82+
83+ if ! builtins.hasAttr "type" spec then
84+ abort "ERROR: niv spec ${name} does not have a 'type' attribute"
85+ else if spec.type == "file" then fetch_file pkgs name spec
86+ else if spec.type == "tarball" then fetch_tarball pkgs name spec
87+ else if spec.type == "git" then fetch_git name spec
88+ else if spec.type == "local" then fetch_local spec
89+ else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
90+ else if spec.type == "builtin-url" then fetch_builtin-url name
91+ else
92+ abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
93+
94+ # If the environment variable NIV_OVERRIDE_${name} is set, then use
95+ # the path directly as opposed to the fetched source.
96+ replace = name: drv:
97+ let
98+ saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
99+ ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
100+ in
101+ if ersatz == "" then drv else ersatz;
102+
103+ # Ports of functions for older nix versions
104+
105+ # a Nix version of mapAttrs if the built-in doesn't exist
106+ mapAttrs = builtins.mapAttrs or (
107+ f: set: with builtins;
108+ listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
109+ );
110+
111+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
112+ range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
113+
114+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
115+ stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
116+
117+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
118+ stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
119+ concatMapStrings = f: list: concatStrings (map f list);
120+ concatStrings = builtins.concatStringsSep "";
121+
122+ # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
123+ optionalAttrs = cond: as: if cond then as else {};
124+
125+ # fetchTarball version that is compatible between all the versions of Nix
126+ builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
127+ let
128+ inherit (builtins) lessThan nixVersion fetchTarball;
129+ in
130+ if lessThan nixVersion "1.12" then
131+ fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
132+ else
133+ fetchTarball attrs;
134+
135+ # fetchurl version that is compatible between all the versions of Nix
136+ builtins_fetchurl = { url, name ? null, sha256 }@attrs:
137+ let
138+ inherit (builtins) lessThan nixVersion fetchurl;
139+ in
140+ if lessThan nixVersion "1.12" then
141+ fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
142+ else
143+ fetchurl attrs;
144+
145+ # Create the final "sources" from the config
146+ mkSources = config:
147+ mapAttrs (
148+ name: spec:
149+ if builtins.hasAttr "outPath" spec
150+ then abort
151+ "The values in sources.json should not have an 'outPath' attribute"
152+ else
153+ spec // { outPath = replace name (fetch config.pkgs name spec); }
154+ ) config.sources;
155+
156+ # The "config" used by the fetchers
157+ mkConfig =
158+ { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
159+ , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
160+ , system ? builtins.currentSystem
161+ , pkgs ? mkPkgs sources system
162+ }: rec {
163+ # The sources, i.e. the attribute set of spec name to spec
164+ inherit sources;
165+
166+ # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
167+ inherit pkgs;
168+ };
169+
170+in
171+mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
benchmarks/oasdiff/gomod2nix.tomlnew file+135
@@ -0,0 +1,135 @@
1+["github.com/davecgh/go-spew"]
2+ sumVersion = "v1.1.1"
3+ ["github.com/davecgh/go-spew".fetch]
4+ type = "git"
5+ url = "https://github.com/davecgh/go-spew"
6+ rev = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
7+ sha256 = "0hka6hmyvp701adzag2g26cxdj47g21x6jz4sc6jjz1mn59d474y"
8+
9+["github.com/getkin/kin-openapi"]
10+ sumVersion = "v0.66.0"
11+ ["github.com/getkin/kin-openapi".fetch]
12+ type = "git"
13+ url = "https://github.com/getkin/kin-openapi"
14+ rev = "6b4444becdebac4ea5658cbe205bac8c27a7ec41"
15+ sha256 = "08njvg2v14k2p3l1fwrmgg21k0fkli2ajac4893j5zky7a72sbiq"
16+
17+["github.com/ghodss/yaml"]
18+ sumVersion = "v1.0.0"
19+ ["github.com/ghodss/yaml".fetch]
20+ type = "git"
21+ url = "https://github.com/ghodss/yaml"
22+ rev = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
23+ sha256 = "0skwmimpy7hlh7pva2slpcplnm912rp3igs98xnqmn859kwa5v8g"
24+
25+["github.com/go-openapi/jsonpointer"]
26+ sumVersion = "v0.19.5"
27+ ["github.com/go-openapi/jsonpointer".fetch]
28+ type = "git"
29+ url = "https://github.com/go-openapi/jsonpointer"
30+ rev = "2446e21cad36eee826e1c2380f0ff747074a2faa"
31+ sha256 = "0azic9nfwywlz4qxvacyi4g668fbbrkcyv15bag02yfcsi8szg5c"
32+
33+["github.com/go-openapi/swag"]
34+ sumVersion = "v0.19.5"
35+ ["github.com/go-openapi/swag".fetch]
36+ type = "git"
37+ url = "https://github.com/go-openapi/swag"
38+ rev = "c3d0f7896d589f3babb99eea24bbc7de98108e72"
39+ sha256 = "1z34vqc5yz6rzvarrvlhkimxx33p74iaxb28l1mv716njvlsmjhg"
40+
41+["github.com/gorilla/mux"]
42+ sumVersion = "v1.8.0"
43+ ["github.com/gorilla/mux".fetch]
44+ type = "git"
45+ url = "https://github.com/gorilla/mux"
46+ rev = "98cb6bf42e086f6af920b965c38cacc07402d51b"
47+ sha256 = "18f0q9qxgq1yh4ji07mqhiydfcwvi56z9d775v7dc7yckj33kpdk"
48+
49+["github.com/kr/pretty"]
50+ sumVersion = "v0.1.0"
51+ ["github.com/kr/pretty".fetch]
52+ type = "git"
53+ url = "https://github.com/kr/pretty"
54+ rev = "73f6ac0b30a98e433b289500d779f50c1a6f0712"
55+ sha256 = "18m4pwg2abd0j9cn5v3k2ksk9ig4vlwxmlw9rrglanziv9l967qp"
56+
57+["github.com/kr/pty"]
58+ sumVersion = "v1.1.1"
59+ ["github.com/kr/pty".fetch]
60+ type = "git"
61+ url = "https://github.com/kr/pty"
62+ rev = "282ce0e5322c82529687d609ee670fac7c7d917c"
63+ sha256 = "0383f0mb9kqjvncqrfpidsf8y6ns5zlrc91c6a74xpyxjwvzl2y6"
64+
65+["github.com/kr/text"]
66+ sumVersion = "v0.1.0"
67+ ["github.com/kr/text".fetch]
68+ type = "git"
69+ url = "https://github.com/kr/text"
70+ rev = "e2ffdb16a802fe2bb95e2e35ff34f0e53aeef34f"
71+ sha256 = "1gm5bsl01apvc84bw06hasawyqm4q84vx1pm32wr9jnd7a8vjgj1"
72+
73+["github.com/mailru/easyjson"]
74+ sumVersion = "v0.0.0-20190626092158-b2ccc519800e"
75+ ["github.com/mailru/easyjson".fetch]
76+ type = "git"
77+ url = "https://github.com/mailru/easyjson"
78+ rev = "b2ccc519800e761ac8000b95e5d57c80a897ff9e"
79+ sha256 = "0q85h383mhbkcjm2vqm72bi8n2252fv3c56q3lclzb8n2crnjcdk"
80+
81+["github.com/pmezard/go-difflib"]
82+ sumVersion = "v1.0.0"
83+ ["github.com/pmezard/go-difflib".fetch]
84+ type = "git"
85+ url = "https://github.com/pmezard/go-difflib"
86+ rev = "792786c7400a136282c1664665ae0a8db921c6c2"
87+ sha256 = "0c1cn55m4rypmscgf0rrb88pn58j3ysvc2d0432dp3c6fqg6cnzw"
88+
89+["github.com/stretchr/objx"]
90+ sumVersion = "v0.1.0"
91+ ["github.com/stretchr/objx".fetch]
92+ type = "git"
93+ url = "https://github.com/stretchr/objx"
94+ rev = "facf9a85c22f48d2f52f2380e4efce1768749a89"
95+ sha256 = "19ynspzjdynbi85xw06mh8ad5j0qa1vryvxjgvbnyrr8rbm4vd8w"
96+
97+["github.com/stretchr/testify"]
98+ sumVersion = "v1.7.0"
99+ ["github.com/stretchr/testify".fetch]
100+ type = "git"
101+ url = "https://github.com/stretchr/testify"
102+ rev = "acba37e5db06f0093b465a7d47822bf13644b66c"
103+ sha256 = "0ixgjsvafr3513pz3r6pmgk074s2dxkll0dadvl25gkf30rkmh10"
104+
105+["github.com/yuin/goldmark"]
106+ sumVersion = "v1.4.0"
107+ ["github.com/yuin/goldmark".fetch]
108+ type = "git"
109+ url = "https://github.com/yuin/goldmark"
110+ rev = "5588d92a56fe1642791cf4aa8e9eae8227cfeecd"
111+ sha256 = "0n3xhna2rnxixjy5d7gfvgjkhddppa8hpzd8i8b68yb2l016g3qk"
112+
113+["gopkg.in/check.v1"]
114+ sumVersion = "v1.0.0-20190902080502-41f04d3bba15"
115+ ["gopkg.in/check.v1".fetch]
116+ type = "git"
117+ url = "https://gopkg.in/check.v1"
118+ rev = "41f04d3bba152ddec2103e299fed053415705330"
119+ sha256 = "0vfk9czmlxmp6wndq8k17rhnjxal764mxfhrccza7nwlia760pjy"
120+
121+["gopkg.in/yaml.v2"]
122+ sumVersion = "v2.3.0"
123+ ["gopkg.in/yaml.v2".fetch]
124+ type = "git"
125+ url = "https://gopkg.in/yaml.v2"
126+ rev = "0b1645d91e851e735d3e23330303ce81f70adbe3"
127+ sha256 = "1md0hlyd9s6myv3663i9l59y74n4xjazifmmyxn43g86fgkc5lzj"
128+
129+["gopkg.in/yaml.v3"]
130+ sumVersion = "v3.0.0-20210107192922-496545a6307b"
131+ ["gopkg.in/yaml.v3".fetch]
132+ type = "git"
133+ url = "https://gopkg.in/yaml.v3"
134+ rev = "496545a6307b2a7d7a710fd516e5e16e8ab62dbc"
135+ sha256 = "06f4lnrp494wqaygv09dggr2dwf3z2bawqhnlnnwiamg5y787k4g"
benchmarks/openapitools/mavenix.locknew file+3511
@@ -0,0 +1,3511 @@
1+{
2+ "artifactId": "openapi-diff-parent",
3+ "deps": [
4+ {
5+ "path": "asm/asm-parent/3.3.1/asm-parent-3.3.1.pom",
6+ "sha1": "72945d9cb6faa5082dcd190da850aa06760e4350"
7+ },
8+ {
9+ "path": "asm/asm/3.3.1/asm-3.3.1.jar",
10+ "sha1": "1d5f20b4ea675e6fab6ab79f1cd60ec268ddc015"
11+ },
12+ {
13+ "path": "asm/asm/3.3.1/asm-3.3.1.pom",
14+ "sha1": "bbcde0189656fa6cc671f27437432ac7e7f95673"
15+ },
16+ {
17+ "path": "backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.jar",
18+ "sha1": "682f7ac17fed79e92f8e87d8455192b63376347b"
19+ },
20+ {
21+ "path": "backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.pom",
22+ "sha1": "24aa8f29c14d1c63225caa6ad5328f1f7a2497a8"
23+ },
24+ {
25+ "path": "classworlds/classworlds/1.1-alpha-2/classworlds-1.1-alpha-2.jar",
26+ "sha1": "05adf2e681c57d7f48038b602f3ca2254ee82d47"
27+ },
28+ {
29+ "path": "classworlds/classworlds/1.1-alpha-2/classworlds-1.1-alpha-2.pom",
30+ "sha1": "8c8ad6a96a8c1168f8b12ec8a227b8261b160b26"
31+ },
32+ {
33+ "path": "classworlds/classworlds/1.1/classworlds-1.1.jar",
34+ "sha1": "60c708f55deeb7c5dfce8a7886ef09cbc1388eca"
35+ },
36+ {
37+ "path": "classworlds/classworlds/1.1/classworlds-1.1.pom",
38+ "sha1": "4703c4199028094698c222c17afea6dcd9f04999"
39+ },
40+ {
41+ "path": "com/coveo/fmt-maven-plugin/2.9.1/fmt-maven-plugin-2.9.1.jar",
42+ "sha1": "b9e23dcda7579bb2136c75a824954458376fc1f9"
43+ },
44+ {
45+ "path": "com/coveo/fmt-maven-plugin/2.9.1/fmt-maven-plugin-2.9.1.pom",
46+ "sha1": "7dd6d3f3d423d1d91f1fc3bc7899f4a042c7e342"
47+ },
48+ {
49+ "path": "com/fasterxml/jackson/core/jackson-annotations/2.10.1/jackson-annotations-2.10.1.pom",
50+ "sha1": "fdcd151d1804dec2025726f598a230e64a7da4d5"
51+ },
52+ {
53+ "path": "com/fasterxml/jackson/core/jackson-annotations/2.11.0/jackson-annotations-2.11.0.pom",
54+ "sha1": "516a81f560864d215c7680f5a00484ddfa8794b5"
55+ },
56+ {
57+ "path": "com/fasterxml/jackson/core/jackson-annotations/2.11.1/jackson-annotations-2.11.1.pom",
58+ "sha1": "b746e11b97ca52619ade1effdb75a786f495f4f7"
59+ },
60+ {
61+ "path": "com/fasterxml/jackson/core/jackson-annotations/2.12.1/jackson-annotations-2.12.1.jar",
62+ "sha1": "aa079f822ddce5548018286d19ccb15c2fc202d7"
63+ },
64+ {
65+ "path": "com/fasterxml/jackson/core/jackson-annotations/2.12.1/jackson-annotations-2.12.1.pom",
66+ "sha1": "9c38fd86d042ec6c2769fd52f5bfd8a8eae1abed"
67+ },
68+ {
69+ "path": "com/fasterxml/jackson/core/jackson-core/2.10.1/jackson-core-2.10.1.pom",
70+ "sha1": "fb8b025a02a6cf5612ad186402c94367c4b912f8"
71+ },
72+ {
73+ "path": "com/fasterxml/jackson/core/jackson-core/2.11.0/jackson-core-2.11.0.pom",
74+ "sha1": "e996f8033f774ea6d197de0edc84d6f14c2ce57e"
75+ },
76+ {
77+ "path": "com/fasterxml/jackson/core/jackson-core/2.11.1/jackson-core-2.11.1.pom",
78+ "sha1": "0a0d8a4a161004cf6d19eaeef9c95c7682da6152"
79+ },
80+ {
81+ "path": "com/fasterxml/jackson/core/jackson-core/2.12.1/jackson-core-2.12.1.jar",
82+ "sha1": "7c5493930e439be6fcec80a9afd6516b8e5e8760"
83+ },
84+ {
85+ "path": "com/fasterxml/jackson/core/jackson-core/2.12.1/jackson-core-2.12.1.pom",
86+ "sha1": "ac12348abc8bb6661e20975ea395c8c995b32b4c"
87+ },
88+ {
89+ "path": "com/fasterxml/jackson/core/jackson-databind/2.10.1/jackson-databind-2.10.1.pom",
90+ "sha1": "ea136b827ada9aebe65ecb47b8a8dacab76c6a89"
91+ },
92+ {
93+ "path": "com/fasterxml/jackson/core/jackson-databind/2.11.0/jackson-databind-2.11.0.pom",
94+ "sha1": "fffc69b81151915509b96cbc7e80ad832b53301d"
95+ },
96+ {
97+ "path": "com/fasterxml/jackson/core/jackson-databind/2.11.1/jackson-databind-2.11.1.pom",
98+ "sha1": "51a50898a694504b98853f909f068d4aa17dc782"
99+ },
100+ {
101+ "path": "com/fasterxml/jackson/core/jackson-databind/2.12.1/jackson-databind-2.12.1.jar",
102+ "sha1": "8a97e00e429c42f74757b0a8cd1d39dddd41524f"
103+ },
104+ {
105+ "path": "com/fasterxml/jackson/core/jackson-databind/2.12.1/jackson-databind-2.12.1.pom",
106+ "sha1": "6d5c05dec274802de5c58b654ff68f772f13125f"
107+ },
108+ {
109+ "path": "com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.10.1/jackson-dataformat-yaml-2.10.1.pom",
110+ "sha1": "d6a8b362e8a7ca52cffe3aeaa30ab85ff88d610f"
111+ },
112+ {
113+ "path": "com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.11.1/jackson-dataformat-yaml-2.11.1.pom",
114+ "sha1": "134a6d50bb1c78e667d226a34f3641f3586cf036"
115+ },
116+ {
117+ "path": "com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.12.1/jackson-dataformat-yaml-2.12.1.jar",
118+ "sha1": "be6bf31ca69a28218daff18caef923ed6e1643e9"
119+ },
120+ {
121+ "path": "com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.12.1/jackson-dataformat-yaml-2.12.1.pom",
122+ "sha1": "776dbfe69bdcc6c3e3a1e020848c65a1fd07cb0c"
123+ },
124+ {
125+ "path": "com/fasterxml/jackson/dataformat/jackson-dataformats-text/2.10.1/jackson-dataformats-text-2.10.1.pom",
126+ "sha1": "3a52b760d354b1203cac90252ff8f82aae7bb043"
127+ },
128+ {
129+ "path": "com/fasterxml/jackson/dataformat/jackson-dataformats-text/2.11.1/jackson-dataformats-text-2.11.1.pom",
130+ "sha1": "7fd5d17a7d147fe4a766d5552c7a5e5bdd874be8"
131+ },
132+ {
133+ "path": "com/fasterxml/jackson/dataformat/jackson-dataformats-text/2.12.1/jackson-dataformats-text-2.12.1.pom",
134+ "sha1": "f03cf5105784f4a4b772802ed718548580c6593f"
135+ },
136+ {
137+ "path": "com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.12.1/jackson-datatype-jsr310-2.12.1.jar",
138+ "sha1": "a245631c624e9c38dd0563c1100243c2f0be8335"
139+ },
140+ {
141+ "path": "com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.12.1/jackson-datatype-jsr310-2.12.1.pom",
142+ "sha1": "d4c62c8a033669bb82dde3bd93bbeabd21e0b3e8"
143+ },
144+ {
145+ "path": "com/fasterxml/jackson/jackson-base/2.10.1/jackson-base-2.10.1.pom",
146+ "sha1": "d0ba31a357e4503ca4f0ef8815d51b20c57edb35"
147+ },
148+ {
149+ "path": "com/fasterxml/jackson/jackson-base/2.11.0/jackson-base-2.11.0.pom",
150+ "sha1": "276bbf4e8376ae502fbb778f457ab8c827905735"
151+ },
152+ {
153+ "path": "com/fasterxml/jackson/jackson-base/2.11.1/jackson-base-2.11.1.pom",
154+ "sha1": "3f035aea01d74bae7a0bdb90064095454eca3730"
155+ },
156+ {
157+ "path": "com/fasterxml/jackson/jackson-base/2.12.1/jackson-base-2.12.1.pom",
158+ "sha1": "2dbd59b818a40450167a1ef3cf511e4c5fd19f69"
159+ },
160+ {
161+ "path": "com/fasterxml/jackson/jackson-bom/2.10.1/jackson-bom-2.10.1.pom",
162+ "sha1": "5893082a4078414e9b19ef1a79ad47727c89fed5"
163+ },
164+ {
165+ "path": "com/fasterxml/jackson/jackson-bom/2.11.0/jackson-bom-2.11.0.pom",
166+ "sha1": "33494ae4ec70fa17a153f42f367b36303cff71ff"
167+ },
168+ {
169+ "path": "com/fasterxml/jackson/jackson-bom/2.11.1/jackson-bom-2.11.1.pom",
170+ "sha1": "619e312d377367fcf8d704c2f575fe62922b7426"
171+ },
172+ {
173+ "path": "com/fasterxml/jackson/jackson-bom/2.12.1/jackson-bom-2.12.1.pom",
174+ "sha1": "47003a8d30c4174338dfc4da85e144cd61af13f3"
175+ },
176+ {
177+ "path": "com/fasterxml/jackson/jackson-parent/2.10/jackson-parent-2.10.pom",
178+ "sha1": "c07f59ea3d696225de2aa318a02b33ad0512b151"
179+ },
180+ {
181+ "path": "com/fasterxml/jackson/jackson-parent/2.11/jackson-parent-2.11.pom",
182+ "sha1": "89f0f8a7f21a54125e0ae1f72e6cdd50b51c87f3"
183+ },
184+ {
185+ "path": "com/fasterxml/jackson/jackson-parent/2.12/jackson-parent-2.12.pom",
186+ "sha1": "7675e7641142bc3c583fc3bf2e30ec9cba076ad9"
187+ },
188+ {
189+ "path": "com/fasterxml/jackson/module/jackson-modules-java8/2.12.1/jackson-modules-java8-2.12.1.pom",
190+ "sha1": "ffac85890402bb43f94f65d5ebd64eace3e436af"
191+ },
192+ {
193+ "path": "com/fasterxml/oss-parent/38/oss-parent-38.pom",
194+ "sha1": "ff6b9e9e40c23235f87a44b463995b47adca8dc9"
195+ },
196+ {
197+ "path": "com/fasterxml/oss-parent/41/oss-parent-41.pom",
198+ "sha1": "2b66e40e928eb5f2f9c1c0da54e3c26f6310cbfa"
199+ },
200+ {
201+ "path": "com/github/java-json-tools/btf/1.3/btf-1.3.jar",
202+ "sha1": "6cf5405e214cbc83337a107cdef8401fb6aa6383"
203+ },
204+ {
205+ "path": "com/github/java-json-tools/btf/1.3/btf-1.3.pom",
206+ "sha1": "0c7801904e438441fea6ab25d0e792b70c1f7399"
207+ },
208+ {
209+ "path": "com/github/java-json-tools/jackson-coreutils-equivalence/1.0/jackson-coreutils-equivalence-1.0.jar",
210+ "sha1": "8b928cf1f95dc5fe6b1648f5da93befab031da19"
211+ },
212+ {
213+ "path": "com/github/java-json-tools/jackson-coreutils-equivalence/1.0/jackson-coreutils-equivalence-1.0.pom",
214+ "sha1": "c71f1ce503ab04453666a1d986cca6e33da68d45"
215+ },
216+ {
217+ "path": "com/github/java-json-tools/jackson-coreutils/2.0/jackson-coreutils-2.0.jar",
218+ "sha1": "6374371261b91b829d10f21256b2feefdf8f0a78"
219+ },
220+ {
221+ "path": "com/github/java-json-tools/jackson-coreutils/2.0/jackson-coreutils-2.0.pom",
222+ "sha1": "561bdf0a38d4e16b7546a1551c1aab29855fc45e"
223+ },
224+ {
225+ "path": "com/github/java-json-tools/json-patch/1.13/json-patch-1.13.jar",
226+ "sha1": "c8b72249e50fe778e7df223e5b1fed1931a4a688"
227+ },
228+ {
229+ "path": "com/github/java-json-tools/json-patch/1.13/json-patch-1.13.pom",
230+ "sha1": "98e392a93101908fc7ce4572a9b204e1536b8bef"
231+ },
232+ {
233+ "path": "com/github/java-json-tools/json-schema-core/1.2.14/json-schema-core-1.2.14.jar",
234+ "sha1": "39d4efcf7e538684200fea15e08d47d0198c19fb"
235+ },
236+ {
237+ "path": "com/github/java-json-tools/json-schema-core/1.2.14/json-schema-core-1.2.14.pom",
238+ "sha1": "20d95413c951cbbaff4a9ce13fb98d29f93a2783"
239+ },
240+ {
241+ "path": "com/github/java-json-tools/json-schema-validator/2.2.14/json-schema-validator-2.2.14.jar",
242+ "sha1": "10c42918adc1fd4454e83bb21365f30df497a076"
243+ },
244+ {
245+ "path": "com/github/java-json-tools/json-schema-validator/2.2.14/json-schema-validator-2.2.14.pom",
246+ "sha1": "28a9a765a2f9b479e8843687a987357b5ec56a37"
247+ },
248+ {
249+ "path": "com/github/java-json-tools/msg-simple/1.2/msg-simple-1.2.jar",
250+ "sha1": "a06afa2d5d75c98e54ab370107930978fc3f9937"
251+ },
252+ {
253+ "path": "com/github/java-json-tools/msg-simple/1.2/msg-simple-1.2.pom",
254+ "sha1": "5b94d70f5d2cf151835ffeef57e543213e35879f"
255+ },
256+ {
257+ "path": "com/github/java-json-tools/uri-template/0.10/uri-template-0.10.jar",
258+ "sha1": "6e8cf7b04f5ed679c76f15e0b19918906d84dbc4"
259+ },
260+ {
261+ "path": "com/github/java-json-tools/uri-template/0.10/uri-template-0.10.pom",
262+ "sha1": "bbb4daf2e61908caf0977b484816c41fa322a46b"
263+ },
264+ {
265+ "path": "com/google/code/findbugs/jsr305/2.0.1/jsr305-2.0.1.pom",
266+ "sha1": "95efa8cea662452bb74b34abe09a93ff47625c8f"
267+ },
268+ {
269+ "path": "com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar",
270+ "sha1": "25ea2e8b0c338a877313bd4672d3fe056ea78f0d"
271+ },
272+ {
273+ "path": "com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.pom",
274+ "sha1": "8d93cdf4d84d7e1de736df607945c6df0730a10f"
275+ },
276+ {
277+ "path": "com/google/collections/google-collections/1.0/google-collections-1.0.pom",
278+ "sha1": "292197f3cb1ebc0dd03e20897e4250b265177286"
279+ },
280+ {
281+ "path": "com/google/errorprone/error_prone_annotations/2.2.0/error_prone_annotations-2.2.0.jar",
282+ "sha1": "88e3c593e9b3586e1c6177f89267da6fc6986f0c"
283+ },
284+ {
285+ "path": "com/google/errorprone/error_prone_annotations/2.2.0/error_prone_annotations-2.2.0.pom",
286+ "sha1": "e28b5b546020f18ea29e2b4756023f53ee91492b"
287+ },
288+ {
289+ "path": "com/google/errorprone/error_prone_annotations/2.3.2/error_prone_annotations-2.3.2.pom",
290+ "sha1": "f9aadf833282cfd743aa5d330f927489ca9c8734"
291+ },
292+ {
293+ "path": "com/google/errorprone/error_prone_annotations/2.3.4/error_prone_annotations-2.3.4.jar",
294+ "sha1": "dac170e4594de319655ffb62f41cbd6dbb5e601e"
295+ },
296+ {
297+ "path": "com/google/errorprone/error_prone_annotations/2.3.4/error_prone_annotations-2.3.4.pom",
298+ "sha1": "9a23fcb83bc8ed502506a8e6c648bf763dc5bcf9"
299+ },
300+ {
301+ "path": "com/google/errorprone/error_prone_parent/2.2.0/error_prone_parent-2.2.0.pom",
302+ "sha1": "72e2f31cb1952eada003d2ba7e82874cfe4b738c"
303+ },
304+ {
305+ "path": "com/google/errorprone/error_prone_parent/2.3.2/error_prone_parent-2.3.2.pom",
306+ "sha1": "ea30b94538922c99fb231a2c9859790831eb0fb0"
307+ },
308+ {
309+ "path": "com/google/errorprone/error_prone_parent/2.3.4/error_prone_parent-2.3.4.pom",
310+ "sha1": "a9b9dd42d174a5f96d6c195525877fc6d0b2028a"
311+ },
312+ {
313+ "path": "com/google/errorprone/javac-shaded/9+181-r4173-1/javac-shaded-9+181-r4173-1.jar",
314+ "sha1": "a399ee380b6d6b6ea53af1cfbcb086b108d1efb7"
315+ },
316+ {
317+ "path": "com/google/errorprone/javac-shaded/9+181-r4173-1/javac-shaded-9+181-r4173-1.pom",
318+ "sha1": "277b9e653add9e37cb6acf37f2b2330ac02dcda5"
319+ },
320+ {
321+ "path": "com/google/google/1/google-1.pom",
322+ "sha1": "c35a5268151b7a1bbb77f7ee94a950f00e32db61"
323+ },
324+ {
325+ "path": "com/google/googlejavaformat/google-java-format-parent/1.7/google-java-format-parent-1.7.pom",
326+ "sha1": "b320014d90fdda640da53e422c9c11b18e613ffc"
327+ },
328+ {
329+ "path": "com/google/googlejavaformat/google-java-format/1.7/google-java-format-1.7.jar",
330+ "sha1": "97cb6afc835d65682edc248e19170a8e4ecfe4c4"
331+ },
332+ {
333+ "path": "com/google/googlejavaformat/google-java-format/1.7/google-java-format-1.7.pom",
334+ "sha1": "f98d4be9cfef8c8a326c63089805e94248954219"
335+ },
336+ {
337+ "path": "com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar",
338+ "sha1": "1dcf1de382a0bf95a3d8b0849546c88bac1292c9"
339+ },
340+ {
341+ "path": "com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.pom",
342+ "sha1": "e8160e78fdaaf7088621dc1649d9dd2dfcf8d0e8"
343+ },
344+ {
345+ "path": "com/google/guava/guava-parent/26.0-android/guava-parent-26.0-android.pom",
346+ "sha1": "a2c0df489614352b7e8e503e274bd1dee5c42a64"
347+ },
348+ {
349+ "path": "com/google/guava/guava-parent/27.0.1-android/guava-parent-27.0.1-android.pom",
350+ "sha1": "87eb68456b29567ac831ffc6f487f1897e58fa7c"
351+ },
352+ {
353+ "path": "com/google/guava/guava-parent/27.0.1-jre/guava-parent-27.0.1-jre.pom",
354+ "sha1": "8f7a96c144da567471d3d763a240c25ba374ebb1"
355+ },
356+ {
357+ "path": "com/google/guava/guava-parent/28.1-android/guava-parent-28.1-android.pom",
358+ "sha1": "a35bc2b0d0477bca2e4a88c9b864de91ce705f5b"
359+ },
360+ {
361+ "path": "com/google/guava/guava-parent/28.2-android/guava-parent-28.2-android.pom",
362+ "sha1": "6db9079b12f809e8ab0f589d2e847a7a0bd9f4d2"
363+ },
364+ {
365+ "path": "com/google/guava/guava/27.0.1-android/guava-27.0.1-android.jar",
366+ "sha1": "b7e1c37f66ef193796ccd7ea6e80c2b05426182d"
367+ },
368+ {
369+ "path": "com/google/guava/guava/27.0.1-android/guava-27.0.1-android.pom",
370+ "sha1": "705c4ba035f86e8e883ce4892db3fecbf2a90b16"
371+ },
372+ {
373+ "path": "com/google/guava/guava/27.0.1-jre/guava-27.0.1-jre.jar",
374+ "sha1": "bd41a290787b5301e63929676d792c507bbc00ae"
375+ },
376+ {
377+ "path": "com/google/guava/guava/27.0.1-jre/guava-27.0.1-jre.pom",
378+ "sha1": "a6ccf3af1d34509e5fb1f5bff675b9ae707ad628"
379+ },
380+ {
381+ "path": "com/google/guava/guava/28.1-android/guava-28.1-android.pom",
382+ "sha1": "ad4f915dab2e5fecba3f440f8f77244647b96499"
383+ },
384+ {
385+ "path": "com/google/guava/guava/28.2-android/guava-28.2-android.jar",
386+ "sha1": "e11db6e27f5d1ec19826848a865c496c798398fa"
387+ },
388+ {
389+ "path": "com/google/guava/guava/28.2-android/guava-28.2-android.pom",
390+ "sha1": "8524e3a9ec839c335c75699514bc6dcb5b541778"
391+ },
392+ {
393+ "path": "com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar",
394+ "sha1": "b421526c5f297295adef1c886e5246c39d4ac629"
395+ },
396+ {
397+ "path": "com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.pom",
398+ "sha1": "1b77ba79f9b2b7dfd4e15ea7bb0d568d5eb9cb8d"
399+ },
400+ {
401+ "path": "com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar",
402+ "sha1": "ed28ded51a8b1c6b112568def5f4b455e6809019"
403+ },
404+ {
405+ "path": "com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.pom",
406+ "sha1": "b964a9414771661bdf35a3f10692a2fb0dd2c866"
407+ },
408+ {
409+ "path": "com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar",
410+ "sha1": "ba035118bc8bac37d7eff77700720999acd9986d"
411+ },
412+ {
413+ "path": "com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.pom",
414+ "sha1": "47e0dd93285dcc6b33181713bc7e8aed66742964"
415+ },
416+ {
417+ "path": "com/googlecode/javaewah/JavaEWAH/1.1.6/JavaEWAH-1.1.6.jar",
418+ "sha1": "94ad16d728b374d65bd897625f3fbb3da223a2b6"
419+ },
420+ {
421+ "path": "com/googlecode/javaewah/JavaEWAH/1.1.6/JavaEWAH-1.1.6.pom",
422+ "sha1": "759dda489d69ebd237d9ee353e67a460274b14f0"
423+ },
424+ {
425+ "path": "com/googlecode/libphonenumber/libphonenumber-parent/8.11.1/libphonenumber-parent-8.11.1.pom",
426+ "sha1": "fe3273c57fc50ef3f6bc4f851cb720e6e2255e4e"
427+ },
428+ {
429+ "path": "com/googlecode/libphonenumber/libphonenumber/8.11.1/libphonenumber-8.11.1.jar",
430+ "sha1": "6bb6115fd5a0bf00964afec358496faea66b7db5"
431+ },
432+ {
433+ "path": "com/googlecode/libphonenumber/libphonenumber/8.11.1/libphonenumber-8.11.1.pom",
434+ "sha1": "394fef7b008490aebe3186ea5dbe546cfb1ee849"
435+ },
436+ {
437+ "path": "com/j2html/j2html/1.5.0/j2html-1.5.0.jar",
438+ "sha1": "4416b2c8735192301711fa54ed97d2361ef90e06"
439+ },
440+ {
441+ "path": "com/j2html/j2html/1.5.0/j2html-1.5.0.pom",
442+ "sha1": "818f0a477f3d3801add2112bf44ba9d6e675c51b"
443+ },
444+ {
445+ "path": "com/jcraft/jsch/0.1.54/jsch-0.1.54.jar",
446+ "sha1": "da3584329a263616e277e15462b387addd1b208d"
447+ },
448+ {
449+ "path": "com/jcraft/jsch/0.1.54/jsch-0.1.54.pom",
450+ "sha1": "8e82e6a2cb5664170faa2a5abdc297e589a37df1"
451+ },
452+ {
453+ "path": "com/jcraft/jzlib/1.1.1/jzlib-1.1.1.jar",
454+ "sha1": "a1551373315ffc2f96130a0e5704f74e151777ba"
455+ },
456+ {
457+ "path": "com/jcraft/jzlib/1.1.1/jzlib-1.1.1.pom",
458+ "sha1": "d990b68017884e9615990c39ef81cf2b5884d464"
459+ },
460+ {
461+ "path": "com/sun/activation/all/1.2.1/all-1.2.1.pom",
462+ "sha1": "efca912f55f71e63ab2eb82552519b66dd123f98"
463+ },
464+ {
465+ "path": "com/sun/mail/all/1.6.2/all-1.6.2.pom",
466+ "sha1": "de5027ae62957f06ba7ff4733a0058871e237121"
467+ },
468+ {
469+ "path": "com/sun/mail/mailapi/1.6.2/mailapi-1.6.2.jar",
470+ "sha1": "208b6439dfbe6713c384ebf54ecd62cd4423cc50"
471+ },
472+ {
473+ "path": "com/sun/mail/mailapi/1.6.2/mailapi-1.6.2.pom",
474+ "sha1": "ab978578ae40ce05d492925a654dcd7154d3bd9a"
475+ },
476+ {
477+ "path": "com/thoughtworks/qdox/qdox/2.0-M8/qdox-2.0-M8.jar",
478+ "sha1": "036dc5cbf2aaf642d9ce7d0338591234ca49fcf0"
479+ },
480+ {
481+ "path": "com/thoughtworks/qdox/qdox/2.0-M8/qdox-2.0-M8.pom",
482+ "sha1": "8fc15cc55411249f3d89973e6ea55a7c4dc8688f"
483+ },
484+ {
485+ "path": "com/thoughtworks/qdox/qdox/2.0-M9/qdox-2.0-M9.jar",
486+ "sha1": "ea940f1cdba9205d03e4f54b9ac0ec988de751dd"
487+ },
488+ {
489+ "path": "com/thoughtworks/qdox/qdox/2.0-M9/qdox-2.0-M9.pom",
490+ "sha1": "5d3e19942fb302f11734b507b1115700b37f2cac"
491+ },
492+ {
493+ "path": "commons-beanutils/commons-beanutils/1.6/commons-beanutils-1.6.pom",
494+ "sha1": "cb6192708aa48ef75e8d04bcde65bc8d5a6ccdbf"
495+ },
496+ {
497+ "path": "commons-beanutils/commons-beanutils/1.7.0/commons-beanutils-1.7.0.jar",
498+ "sha1": "5675fd96b29656504b86029551973d60fb41339b"
499+ },
500+ {
501+ "path": "commons-beanutils/commons-beanutils/1.7.0/commons-beanutils-1.7.0.pom",
502+ "sha1": "19eca029edacc1be30030faf43ea6acb30556d1a"
503+ },
504+ {
505+ "path": "commons-cli/commons-cli/1.0/commons-cli-1.0.jar",
506+ "sha1": "6dac9733315224fc562f6268df58e92d65fd0137"
507+ },
508+ {
509+ "path": "commons-cli/commons-cli/1.0/commons-cli-1.0.pom",
510+ "sha1": "bc51fd74ed7c8ccf75b3abc84b3613d6ba60eb89"
511+ },
512+ {
513+ "path": "commons-cli/commons-cli/1.4/commons-cli-1.4.jar",
514+ "sha1": "c51c00206bb913cd8612b24abd9fa98ae89719b1"
515+ },
516+ {
517+ "path": "commons-cli/commons-cli/1.4/commons-cli-1.4.pom",
518+ "sha1": "c5aed4264ff37247043f6dcb6613d994ea7f8473"
519+ },
520+ {
521+ "path": "commons-codec/commons-codec/1.11/commons-codec-1.11.jar",
522+ "sha1": "3acb4705652e16236558f0f4f2192cc33c3bd189"
523+ },
524+ {
525+ "path": "commons-codec/commons-codec/1.11/commons-codec-1.11.pom",
526+ "sha1": "093ee1760aba62d6896d578bd7d247d0fa52f0e7"
527+ },
528+ {
529+ "path": "commons-codec/commons-codec/1.2/commons-codec-1.2.jar",
530+ "sha1": "397f4731a9f9b6eb1907e224911c77ea3aa27a8b"
531+ },
532+ {
533+ "path": "commons-codec/commons-codec/1.2/commons-codec-1.2.pom",
534+ "sha1": "3924208ea1e84feb88701e9a5000bc65c66fb335"
535+ },
536+ {
537+ "path": "commons-codec/commons-codec/1.9/commons-codec-1.9.pom",
538+ "sha1": "f5357ff0f308600af3660bf00a8be3415a335723"
539+ },
540+ {
541+ "path": "commons-collections/commons-collections/2.0/commons-collections-2.0.pom",
542+ "sha1": "b0d78d06e725d7f8176256eaeceb9d5b3f0a7bca"
543+ },
544+ {
545+ "path": "commons-collections/commons-collections/2.1/commons-collections-2.1.pom",
546+ "sha1": "03ac124c9f50b403afc9819e1f430d6883e77213"
547+ },
548+ {
549+ "path": "commons-collections/commons-collections/3.1/commons-collections-3.1.pom",
550+ "sha1": "f1afb3351823e726793a165ca37dced8f0191370"
551+ },
552+ {
553+ "path": "commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar",
554+ "sha1": "761ea405b9b37ced573d2df0d1e3a4e0f9edc668"
555+ },
556+ {
557+ "path": "commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.pom",
558+ "sha1": "c812635cfb96cd2431ee315e73418eed86aeb5e4"
559+ },
560+ {
561+ "path": "commons-collections/commons-collections/3.2/commons-collections-3.2.pom",
562+ "sha1": "0c8e56dc5476c517f1596f0686d72f51ef24d9e3"
563+ },
564+ {
565+ "path": "commons-digester/commons-digester/1.6/commons-digester-1.6.jar",
566+ "sha1": "e2822f655f2c182681c2cf27f224a425ccb2983d"
567+ },
568+ {
569+ "path": "commons-digester/commons-digester/1.6/commons-digester-1.6.pom",
570+ "sha1": "807b7186d68503e8a596c19f9d6ff2c70416967c"
571+ },
572+ {
573+ "path": "commons-httpclient/commons-httpclient/3.1/commons-httpclient-3.1.jar",
574+ "sha1": "964cd74171f427720480efdec40a7c7f6e58426a"
575+ },
576+ {
577+ "path": "commons-httpclient/commons-httpclient/3.1/commons-httpclient-3.1.pom",
578+ "sha1": "7e64d764d7f7ebc75ae3920490fcb58fbaf504a8"
579+ },
580+ {
581+ "path": "commons-io/commons-io/1.4/commons-io-1.4.jar",
582+ "sha1": "a8762d07e76cfde2395257a5da47ba7c1dbd3dce"
583+ },
584+ {
585+ "path": "commons-io/commons-io/1.4/commons-io-1.4.pom",
586+ "sha1": "526f34cad0a113787f3eb8ee1d0fe0abebcba887"
587+ },
588+ {
589+ "path": "commons-io/commons-io/2.4/commons-io-2.4.pom",
590+ "sha1": "9ece23effe8bce3904f3797a76b1ba6ab681e1b9"
591+ },
592+ {
593+ "path": "commons-io/commons-io/2.5/commons-io-2.5.jar",
594+ "sha1": "2852e6e05fbb95076fc091f6d1780f1f8fe35e0f"
595+ },
596+ {
597+ "path": "commons-io/commons-io/2.5/commons-io-2.5.pom",
598+ "sha1": "7e39112810f6096061c43504188d18edc7d7eece"
599+ },
600+ {
601+ "path": "commons-io/commons-io/2.6/commons-io-2.6.jar",
602+ "sha1": "815893df5f31da2ece4040fe0a12fd44b577afaf"
603+ },
604+ {
605+ "path": "commons-io/commons-io/2.6/commons-io-2.6.pom",
606+ "sha1": "5060835593e5b6ed18c82fc2e782f0a3c30a00b1"
607+ },
608+ {
609+ "path": "commons-lang/commons-lang/2.1/commons-lang-2.1.jar",
610+ "sha1": "4763ecc9d78781c915c07eb03e90572c7ff04205"
611+ },
612+ {
613+ "path": "commons-lang/commons-lang/2.1/commons-lang-2.1.pom",
614+ "sha1": "a34d992202615804c534953aba402de55d8ee47c"
615+ },
616+ {
617+ "path": "commons-lang/commons-lang/2.5/commons-lang-2.5.jar",
618+ "sha1": "b0236b252e86419eef20c31a44579d2aee2f0a69"
619+ },
620+ {
621+ "path": "commons-lang/commons-lang/2.6/commons-lang-2.6.jar",
622+ "sha1": "0ce1edb914c94ebc388f086c6827e8bdeec71ac2"
623+ },
624+ {
625+ "path": "commons-lang/commons-lang/2.6/commons-lang-2.6.pom",
626+ "sha1": "347d60b180fa80e5699d8e2cb72c99c93dda5454"
627+ },
628+ {
629+ "path": "commons-logging/commons-logging-api/1.1/commons-logging-api-1.1.pom",
630+ "sha1": "825395875e4a7ac53277f5f746085a3e13a04248"
631+ },
632+ {
633+ "path": "commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.pom",
634+ "sha1": "b7de43bb310eb1dbfd00a34cec30500fa13cb577"
635+ },
636+ {
637+ "path": "commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar",
638+ "sha1": "f029a2aefe2b3e1517573c580f948caac31b1056"
639+ },
640+ {
641+ "path": "commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.pom",
642+ "sha1": "7d32e7520b801cabc3dc704d2afe59d020d00c45"
643+ },
644+ {
645+ "path": "commons-logging/commons-logging/1.0/commons-logging-1.0.pom",
646+ "sha1": "4f58df6cca7ad7b863e8186e5dc25a8ef502e374"
647+ },
648+ {
649+ "path": "commons-logging/commons-logging/1.2/commons-logging-1.2.pom",
650+ "sha1": "075c03ba4b01932842a996ef8d3fc1ab61ddeac2"
651+ },
652+ {
653+ "path": "commons-validator/commons-validator/1.2.0/commons-validator-1.2.0.jar",
654+ "sha1": "13dcebc00d206605bea72f6191b80370eb3ca805"
655+ },
656+ {
657+ "path": "commons-validator/commons-validator/1.2.0/commons-validator-1.2.0.pom",
658+ "sha1": "a7992acb52332d17c1bd9f7f774361b68b183c23"
659+ },
660+ {
661+ "path": "io/github/phillipuniverse/githook-maven-plugin/1.0.5/githook-maven-plugin-1.0.5.jar",
662+ "sha1": "79f5d906dbd88c654d2d4aabd4f7f26447782b05"
663+ },
664+ {
665+ "path": "io/github/phillipuniverse/githook-maven-plugin/1.0.5/githook-maven-plugin-1.0.5.pom",
666+ "sha1": "db15a1a8feb7f44a4bcaf3ec3914bd808017473c"
667+ },
668+ {
669+ "path": "io/swagger/core/v3/swagger-annotations/2.1.10/swagger-annotations-2.1.10.jar",
670+ "sha1": "1eec58d3db42dcefac76fa47211812c4782b1342"
671+ },
672+ {
673+ "path": "io/swagger/core/v3/swagger-annotations/2.1.10/swagger-annotations-2.1.10.pom",
674+ "sha1": "22f5429db8b61a40a4adc520062b811d8a474e1b"
675+ },
676+ {
677+ "path": "io/swagger/core/v3/swagger-core/2.1.10/swagger-core-2.1.10.jar",
678+ "sha1": "2400f32e387ade9ca015552d9ac23d1139c9884d"
679+ },
680+ {
681+ "path": "io/swagger/core/v3/swagger-core/2.1.10/swagger-core-2.1.10.pom",
682+ "sha1": "c4a78b843ca77156d6a4282d5a6533214e511b88"
683+ },
684+ {
685+ "path": "io/swagger/core/v3/swagger-models/2.1.10/swagger-models-2.1.10.jar",
686+ "sha1": "e577371a45e67ee22fa3b31675ff8a333054de4b"
687+ },
688+ {
689+ "path": "io/swagger/core/v3/swagger-models/2.1.10/swagger-models-2.1.10.pom",
690+ "sha1": "7a9293f9e8b8be13d4570ea4fac1e727cbc89210"
691+ },
692+ {
693+ "path": "io/swagger/core/v3/swagger-project/2.1.10/swagger-project-2.1.10.pom",
694+ "sha1": "3cb602835c36d643b42f35c21eb82abe0fdf47b4"
695+ },
696+ {
697+ "path": "io/swagger/parser/v3/swagger-parser-core/2.0.27/swagger-parser-core-2.0.27.jar",
698+ "sha1": "06e3a0b827ad5c519540963b61633eb88c4eb2b3"
699+ },
700+ {
701+ "path": "io/swagger/parser/v3/swagger-parser-core/2.0.27/swagger-parser-core-2.0.27.pom",
702+ "sha1": "1991007131f2c9f9ac7cd6c2c599bf41c2cc545f"
703+ },
704+ {
705+ "path": "io/swagger/parser/v3/swagger-parser-project/2.0.27/swagger-parser-project-2.0.27.pom",
706+ "sha1": "4db7dd58f920f974975463bcad388c81a3171470"
707+ },
708+ {
709+ "path": "io/swagger/parser/v3/swagger-parser-v2-converter/2.0.27/swagger-parser-v2-converter-2.0.27.jar",
710+ "sha1": "c827b8e82654f7ab2e575e56b7f9a8ca178e67bd"
711+ },
712+ {
713+ "path": "io/swagger/parser/v3/swagger-parser-v2-converter/2.0.27/swagger-parser-v2-converter-2.0.27.pom",
714+ "sha1": "d9e589a7b6f31cb3f801da0f1b172160108ef3a2"
715+ },
716+ {
717+ "path": "io/swagger/parser/v3/swagger-parser-v3/2.0.27/swagger-parser-v3-2.0.27.jar",
718+ "sha1": "304f736165d05944e3fc3bfa40ec09f65b985a23"
719+ },
720+ {
721+ "path": "io/swagger/parser/v3/swagger-parser-v3/2.0.27/swagger-parser-v3-2.0.27.pom",
722+ "sha1": "1d096d5386f3b519724377b9774c45ff0228826e"
723+ },
724+ {
725+ "path": "io/swagger/parser/v3/swagger-parser/2.0.27/swagger-parser-2.0.27.jar",
726+ "sha1": "63369fb7dda733feed9a2df2c5eb414ac7561a0e"
727+ },
728+ {
729+ "path": "io/swagger/parser/v3/swagger-parser/2.0.27/swagger-parser-2.0.27.pom",
730+ "sha1": "c43ecebd10022c75bad76e8e10956834a7f9973e"
731+ },
732+ {
733+ "path": "io/swagger/swagger-annotations/1.6.1/swagger-annotations-1.6.1.pom",
734+ "sha1": "43769ab44afc59a0b3acc2a05aabb912c406c0c8"
735+ },
736+ {
737+ "path": "io/swagger/swagger-annotations/1.6.2/swagger-annotations-1.6.2.jar",
738+ "sha1": "313913e603eaf3bb2c3b05079046ec07bb61f8c6"
739+ },
740+ {
741+ "path": "io/swagger/swagger-annotations/1.6.2/swagger-annotations-1.6.2.pom",
742+ "sha1": "3f95a7e66c8d71a7b6144d13bb45aca44c27caaf"
743+ },
744+ {
745+ "path": "io/swagger/swagger-compat-spec-parser/1.0.55/swagger-compat-spec-parser-1.0.55.jar",
746+ "sha1": "53347a00aaafa1cfb4b68b41563d6fbb3c1d86a0"
747+ },
748+ {
749+ "path": "io/swagger/swagger-compat-spec-parser/1.0.55/swagger-compat-spec-parser-1.0.55.pom",
750+ "sha1": "e1a68d7d9de27d86765ae3f67526f54ffcfea2f4"
751+ },
752+ {
753+ "path": "io/swagger/swagger-core/1.6.1/swagger-core-1.6.1.pom",
754+ "sha1": "cda5d0b22d090aa4e8d50dd6756044d3c6d87e5c"
755+ },
756+ {
757+ "path": "io/swagger/swagger-core/1.6.2/swagger-core-1.6.2.jar",
758+ "sha1": "4f062ad1aebb1255b84c851d00694cc7949de832"
759+ },
760+ {
761+ "path": "io/swagger/swagger-core/1.6.2/swagger-core-1.6.2.pom",
762+ "sha1": "534fb8fd889f0ab325ee4689971e1f62022b5b39"
763+ },
764+ {
765+ "path": "io/swagger/swagger-models/1.6.1/swagger-models-1.6.1.pom",
766+ "sha1": "dad12b91d115af4a0f224b3513b1049211382a4f"
767+ },
768+ {
769+ "path": "io/swagger/swagger-models/1.6.2/swagger-models-1.6.2.jar",
770+ "sha1": "887697058d8464462e8fd6d23c8461e90aec8c08"
771+ },
772+ {
773+ "path": "io/swagger/swagger-models/1.6.2/swagger-models-1.6.2.pom",
774+ "sha1": "24a8e6dfc8078fb2d26e4859ee6cbe8129fd89c1"
775+ },
776+ {
777+ "path": "io/swagger/swagger-parser-project/1.0.55/swagger-parser-project-1.0.55.pom",
778+ "sha1": "7add46a1d32db32e3dde17445c042599e98ba656"
779+ },
780+ {
781+ "path": "io/swagger/swagger-parser/1.0.55/swagger-parser-1.0.55.jar",
782+ "sha1": "4d1d07b4730e738b1ff11683973c5ddfca7f514e"
783+ },
784+ {
785+ "path": "io/swagger/swagger-parser/1.0.55/swagger-parser-1.0.55.pom",
786+ "sha1": "05f85ea462d75bed8afe91fcc7636a2fb93f0429"
787+ },
788+ {
789+ "path": "io/swagger/swagger-project/1.6.1/swagger-project-1.6.1.pom",
790+ "sha1": "9981865f6e64187bf023d8aac0f25ddcd750662a"
791+ },
792+ {
793+ "path": "io/swagger/swagger-project/1.6.2/swagger-project-1.6.2.pom",
794+ "sha1": "f33f1fd09542c95cd62267202f1596561db845be"
795+ },
796+ {
797+ "path": "jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1.jar",
798+ "sha1": "562a587face36ec7eff2db7f2fc95425c6602bc1"
799+ },
800+ {
801+ "path": "jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1.pom",
802+ "sha1": "b9c1b2502949970360efe8d75ec5268d87d38a82"
803+ },
804+ {
805+ "path": "jakarta/validation/jakarta.validation-api/2.0.2/jakarta.validation-api-2.0.2.jar",
806+ "sha1": "5eacc6522521f7eacb081f95cee1e231648461e7"
807+ },
808+ {
809+ "path": "jakarta/validation/jakarta.validation-api/2.0.2/jakarta.validation-api-2.0.2.pom",
810+ "sha1": "fc029778f5494ed05e5833f8bdb57e36dbda38aa"
811+ },
812+ {
813+ "path": "jakarta/xml/bind/jakarta.xml.bind-api-parent/2.3.2/jakarta.xml.bind-api-parent-2.3.2.pom",
814+ "sha1": "7be72e8345e33f747d5d813e313abd8df25f259e"
815+ },
816+ {
817+ "path": "jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2.jar",
818+ "sha1": "8d49996a4338670764d7ca4b85a1c4ccf7fe665d"
819+ },
820+ {
821+ "path": "jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2.pom",
822+ "sha1": "6142021e7186bf29f5f7639b968cfe250ce086dd"
823+ },
824+ {
825+ "path": "javax/annotation/jsr250-api/1.0/jsr250-api-1.0.jar",
826+ "sha1": "5025422767732a1ab45d93abfea846513d742dcf"
827+ },
828+ {
829+ "path": "javax/annotation/jsr250-api/1.0/jsr250-api-1.0.pom",
830+ "sha1": "828184cb963d953865b5941e416999e376b1c82a"
831+ },
832+ {
833+ "path": "javax/enterprise/cdi-api/1.0/cdi-api-1.0.jar",
834+ "sha1": "44c453f60909dfc223552ace63e05c694215156b"
835+ },
836+ {
837+ "path": "javax/enterprise/cdi-api/1.0/cdi-api-1.0.pom",
838+ "sha1": "b79b64c2b1cd6ddc1663f9f48dbf527262a2c3e5"
839+ },
840+ {
841+ "path": "javax/inject/javax.inject/1/javax.inject-1.jar",
842+ "sha1": "6975da39a7040257bd51d21a231b76c915872d38"
843+ },
844+ {
845+ "path": "javax/inject/javax.inject/1/javax.inject-1.pom",
846+ "sha1": "b8e00a8a0deb0ebef447570e37ff8146ccd92cbe"
847+ },
848+ {
849+ "path": "javax/servlet/servlet-api/2.5/servlet-api-2.5.jar",
850+ "sha1": "5959582d97d8b61f4d154ca9e495aafd16726e34"
851+ },
852+ {
853+ "path": "javax/validation/validation-api/1.1.0.Final/validation-api-1.1.0.Final.jar",
854+ "sha1": "8613ae82954779d518631e05daa73a6a954817d5"
855+ },
856+ {
857+ "path": "javax/validation/validation-api/1.1.0.Final/validation-api-1.1.0.Final.pom",
858+ "sha1": "0d2ad4d1498d1048abc6c6948fd3f835d8fdafb0"
859+ },
860+ {
861+ "path": "joda-time/joda-time/2.10.5/joda-time-2.10.5.jar",
862+ "sha1": "7f1d89817cd20a32444d5ab4160f035ab9b864e7"
863+ },
864+ {
865+ "path": "joda-time/joda-time/2.10.5/joda-time-2.10.5.pom",
866+ "sha1": "2523a5fb9c0b367fc734b33c8da600889472bd46"
867+ },
868+ {
869+ "path": "junit/junit/3.8.1/junit-3.8.1.jar",
870+ "sha1": "99129f16442844f6a4a11ae22fbbee40b14d774f"
871+ },
872+ {
873+ "path": "junit/junit/3.8.1/junit-3.8.1.pom",
874+ "sha1": "16d74791c801c89b0071b1680ea0bc85c93417bb"
875+ },
876+ {
877+ "path": "junit/junit/3.8.2/junit-3.8.2.pom",
878+ "sha1": "c735a15ca8fc2ea77db963c71ade153ffeb8212e"
879+ },
880+ {
881+ "path": "junit/junit/4.12/junit-4.12.jar",
882+ "sha1": "2973d150c0dc1fefe998f834810d68f278ea58ec"
883+ },
884+ {
885+ "path": "junit/junit/4.12/junit-4.12.pom",
886+ "sha1": "35fb238baee3f3af739074d723279ebea2028398"
887+ },
888+ {
889+ "path": "junit/junit/4.13.1/junit-4.13.1.jar",
890+ "sha1": "cdd00374f1fee76b11e2a9d127405aa3f6be5b6a"
891+ },
892+ {
893+ "path": "junit/junit/4.13.1/junit-4.13.1.pom",
894+ "sha1": "643e8b4c40dca9f0b0abd8125d378d9f47d7d69e"
895+ },
896+ {
897+ "path": "log4j/log4j/1.2.12/log4j-1.2.12.pom",
898+ "sha1": "70545179454d298d1ff01335fbec3c2acfd381d5"
899+ },
900+ {
901+ "path": "log4j/log4j/1.2.17/log4j-1.2.17.jar",
902+ "sha1": "5af35056b4d257e4b64b9e8069c0746e8b08629f"
903+ },
904+ {
905+ "path": "log4j/log4j/1.2.17/log4j-1.2.17.pom",
906+ "sha1": "309d3cac016db1a4cd4565ea2b95c0bdf040f8d1"
907+ },
908+ {
909+ "path": "net/java/jvnet-parent/1/jvnet-parent-1.pom",
910+ "sha1": "b55a1b046dbe82acdee8edde7476eebcba1e57d8"
911+ },
912+ {
913+ "path": "net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar",
914+ "sha1": "4fdac2fbe92dfad86aa6e9301736f6b4342a3f5c"
915+ },
916+ {
917+ "path": "net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.pom",
918+ "sha1": "c761a09cd9a4695b242c1fc35322d5b1659df7ed"
919+ },
920+ {
921+ "path": "org/apache/apache/10/apache-10.pom",
922+ "sha1": "48296e511366fa13aad48c58d8e09721774abec6"
923+ },
924+ {
925+ "path": "org/apache/apache/11/apache-11.pom",
926+ "sha1": "cb35e3b8eb7f1adbdc91e015b60d0da3a4e16c4f"
927+ },
928+ {
929+ "path": "org/apache/apache/13/apache-13.pom",
930+ "sha1": "15aff1faaec4963617f07dbe8e603f0adabc3a12"
931+ },
932+ {
933+ "path": "org/apache/apache/14/apache-14.pom",
934+ "sha1": "5c7956a91f3faaa9534cdc2b571c90bde2235157"
935+ },
936+ {
937+ "path": "org/apache/apache/16/apache-16.pom",
938+ "sha1": "8a90e31780e5cd0685ccaf25836c66e3b4e163b7"
939+ },
940+ {
941+ "path": "org/apache/apache/17/apache-17.pom",
942+ "sha1": "c1685ef8de6047fdad5e5fce99a8ccd80fc8b659"
943+ },
944+ {
945+ "path": "org/apache/apache/18/apache-18.pom",
946+ "sha1": "bd408bbea3840f2c7f914b29403e39a90f84fd5f"
947+ },
948+ {
949+ "path": "org/apache/apache/19/apache-19.pom",
950+ "sha1": "db8bb0231dcbda5011926dbaca1a7ce652fd5517"
951+ },
952+ {
953+ "path": "org/apache/apache/21/apache-21.pom",
954+ "sha1": "649b700a1b2b4a1d87e7ae8e3f47bfe101b2a4a5"
955+ },
956+ {
957+ "path": "org/apache/apache/23/apache-23.pom",
958+ "sha1": "0404949e96725e63a10a6d8f9d9b521948d170d5"
959+ },
960+ {
961+ "path": "org/apache/apache/3/apache-3.pom",
962+ "sha1": "1bc0010136a890e2fd38d901a0b7ecdf0e3f9871"
963+ },
964+ {
965+ "path": "org/apache/apache/4/apache-4.pom",
966+ "sha1": "602b647986c1d24301bc3d70e5923696bc7f1401"
967+ },
968+ {
969+ "path": "org/apache/apache/5/apache-5.pom",
970+ "sha1": "a99e211eb2be05af269c489b0f1abb9e8469fbca"
971+ },
972+ {
973+ "path": "org/apache/apache/6/apache-6.pom",
974+ "sha1": "70e78921afc16d914e65611d18ab1b2d6cb20e57"
975+ },
976+ {
977+ "path": "org/apache/apache/7/apache-7.pom",
978+ "sha1": "a5f679b14bb06a3cb3769eb04e228c8b9e12908f"
979+ },
980+ {
981+ "path": "org/apache/apache/9/apache-9.pom",
982+ "sha1": "de55d73a30c7521f3d55e8141d360ffbdfd88caa"
983+ },
984+ {
985+ "path": "org/apache/commons/commons-collections4/4.4/commons-collections4-4.4.jar",
986+ "sha1": "62ebe7544cb7164d87e0637a2a6a2bdc981395e8"
987+ },
988+ {
989+ "path": "org/apache/commons/commons-collections4/4.4/commons-collections4-4.4.pom",
990+ "sha1": "05428d42492ca170947632194080eb9432fbdf6c"
991+ },
992+ {
993+ "path": "org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar",
994+ "sha1": "c6842c86792ff03b9f1d1fe2aab8dc23aa6c6f0e"
995+ },
996+ {
997+ "path": "org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.pom",
998+ "sha1": "302d01a9279f7a400b1e767be60f12c02a5cf513"
999+ },
1000+ {
1001+ "path": "org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.jar",
1002+ "sha1": "5fe28b9518e58819180a43a850fbc0dd24b7c050"
1003+ },
1004+ {
1005+ "path": "org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.pom",
1006+ "sha1": "fd6eccbd05d55177e2f5e6d9da6f8d120751ab72"
1007+ },
1008+ {
1009+ "path": "org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar",
1010+ "sha1": "557edd918fd41f9260963583ebf5a61a43a6b423"
1011+ },
1012+ {
1013+ "path": "org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.pom",
1014+ "sha1": "c445be3b6442b41cbea539d4218be3aea9428a55"
1015+ },
1016+ {
1017+ "path": "org/apache/commons/commons-parent/17/commons-parent-17.pom",
1018+ "sha1": "84bc2f457fac92c947cde9c15c81786ded79b3c1"
1019+ },
1020+ {
1021+ "path": "org/apache/commons/commons-parent/25/commons-parent-25.pom",
1022+ "sha1": "67b84199ca4acf0d8fbc5256d90b80f746737e94"
1023+ },
1024+ {
1025+ "path": "org/apache/commons/commons-parent/32/commons-parent-32.pom",
1026+ "sha1": "0e51c4223003c2c7c63f38d7b8823e40eb06bd1f"
1027+ },
1028+ {
1029+ "path": "org/apache/commons/commons-parent/34/commons-parent-34.pom",
1030+ "sha1": "1f6be162a806d8343e3cd238dd728558532473a5"
1031+ },
1032+ {
1033+ "path": "org/apache/commons/commons-parent/37/commons-parent-37.pom",
1034+ "sha1": "a85dfae7a1295e5aed75bd952e6795832e4abcc5"
1035+ },
1036+ {
1037+ "path": "org/apache/commons/commons-parent/39/commons-parent-39.pom",
1038+ "sha1": "4bc32d3cda9f07814c548492af7bf19b21798d46"
1039+ },
1040+ {
1041+ "path": "org/apache/commons/commons-parent/42/commons-parent-42.pom",
1042+ "sha1": "35d45eda74fe511d3d60b68e1dac29ed55043354"
1043+ },
1044+ {
1045+ "path": "org/apache/commons/commons-parent/48/commons-parent-48.pom",
1046+ "sha1": "1cdeb626cf4f0cec0f171ec838a69922efc6ef95"
1047+ },
1048+ {
1049+ "path": "org/apache/commons/commons-parent/52/commons-parent-52.pom",
1050+ "sha1": "004ee86dedc66d0010ccdc29e5a4ce014c057854"
1051+ },
1052+ {
1053+ "path": "org/apache/commons/commons-parent/7/commons-parent-7.pom",
1054+ "sha1": "95db361d9db1474346b2bde93e5402281909144c"
1055+ },
1056+ {
1057+ "path": "org/apache/commons/commons-parent/9/commons-parent-9.pom",
1058+ "sha1": "217cc375e25b647a61956e1d6a88163f9e3a387c"
1059+ },
1060+ {
1061+ "path": "org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar",
1062+ "sha1": "733db77aa8d9b2d68015189df76ab06304406e50"
1063+ },
1064+ {
1065+ "path": "org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.pom",
1066+ "sha1": "56f6338b324e438307e1f2c2b33bd02268310fc2"
1067+ },
1068+ {
1069+ "path": "org/apache/httpcomponents/httpcomponents-client/4.5.2/httpcomponents-client-4.5.2.pom",
1070+ "sha1": "55d500e6c1e98ffbb00c35bee72fabc255c22108"
1071+ },
1072+ {
1073+ "path": "org/apache/httpcomponents/httpcomponents-core/4.4.4/httpcomponents-core-4.4.4.pom",
1074+ "sha1": "84c5600018f58510ef3d2c3b5d218bea5d51bbbe"
1075+ },
1076+ {
1077+ "path": "org/apache/httpcomponents/httpcore/4.4.4/httpcore-4.4.4.jar",
1078+ "sha1": "b31526a230871fbe285fbcbe2813f9c0839ae9b0"
1079+ },
1080+ {
1081+ "path": "org/apache/httpcomponents/httpcore/4.4.4/httpcore-4.4.4.pom",
1082+ "sha1": "2feaed055f70af1aafd223137e4bd456decc5995"
1083+ },
1084+ {
1085+ "path": "org/apache/httpcomponents/project/7/project-7.pom",
1086+ "sha1": "c486760d8e0eafe8d4932450e386c2805364f782"
1087+ },
1088+ {
1089+ "path": "org/apache/maven/doxia/doxia-core/1.0/doxia-core-1.0.jar",
1090+ "sha1": "e94c3303b09923f8cd7916a59702ef5972033f5d"
1091+ },
1092+ {
1093+ "path": "org/apache/maven/doxia/doxia-core/1.0/doxia-core-1.0.pom",
1094+ "sha1": "d4f85b43d096d6346af131b9d184847c67d0b405"
1095+ },
1096+ {
1097+ "path": "org/apache/maven/doxia/doxia-core/1.4/doxia-core-1.4.jar",
1098+ "sha1": "1e9ee5aa729da72e9e9884462782c005592d2075"
1099+ },
1100+ {
1101+ "path": "org/apache/maven/doxia/doxia-decoration-model/1.0/doxia-decoration-model-1.0.jar",
1102+ "sha1": "040cc4c68fcc197885c4d98f89588bd0445c7449"
1103+ },
1104+ {
1105+ "path": "org/apache/maven/doxia/doxia-decoration-model/1.0/doxia-decoration-model-1.0.pom",
1106+ "sha1": "ce88deb4d18e5ecd4b23bb3e4c60b6bd842bb27f"
1107+ },
1108+ {
1109+ "path": "org/apache/maven/doxia/doxia-decoration-model/1.4/doxia-decoration-model-1.4.jar",
1110+ "sha1": "ffa7fabafef8ba0accc794d025f9790320220e1e"
1111+ },
1112+ {
1113+ "path": "org/apache/maven/doxia/doxia-integration-tools/1.5/doxia-integration-tools-1.5.jar",
1114+ "sha1": "ee43d4ccb9e5cc4067ac4f4de9b50e89de2f1191"
1115+ },
1116+ {
1117+ "path": "org/apache/maven/doxia/doxia-logging-api/1.4/doxia-logging-api-1.4.jar",
1118+ "sha1": "fd0ab30404ac0fca5f672eee70acf5d17a1ea856"
1119+ },
1120+ {
1121+ "path": "org/apache/maven/doxia/doxia-module-apt/1.0/doxia-module-apt-1.0.jar",
1122+ "sha1": "de385703452b5b9029504df97b763f7f48e8bf42"
1123+ },
1124+ {
1125+ "path": "org/apache/maven/doxia/doxia-module-apt/1.0/doxia-module-apt-1.0.pom",
1126+ "sha1": "4d78dfaba27a352590ea86e6eaa80284c004e603"
1127+ },
1128+ {
1129+ "path": "org/apache/maven/doxia/doxia-module-apt/1.4/doxia-module-apt-1.4.jar",
1130+ "sha1": "2b6fc70f6906e74eee049cc30f8385e49381c16f"
1131+ },
1132+ {
1133+ "path": "org/apache/maven/doxia/doxia-module-fml/1.0/doxia-module-fml-1.0.jar",
1134+ "sha1": "f837b5f530c95b5551d94d792da31737e678eaa1"
1135+ },
1136+ {
1137+ "path": "org/apache/maven/doxia/doxia-module-fml/1.0/doxia-module-fml-1.0.pom",
1138+ "sha1": "dcb9b6d9fbd98857242891f7922e5f032ab56897"
1139+ },
1140+ {
1141+ "path": "org/apache/maven/doxia/doxia-module-fml/1.4/doxia-module-fml-1.4.jar",
1142+ "sha1": "d27851cfa0a355070acdc0482de3e94c0140b5db"
1143+ },
1144+ {
1145+ "path": "org/apache/maven/doxia/doxia-module-markdown/1.4/doxia-module-markdown-1.4.jar",
1146+ "sha1": "90c587acc8b13dea639ffeb43854165a6531a011"
1147+ },
1148+ {
1149+ "path": "org/apache/maven/doxia/doxia-module-xdoc/1.0/doxia-module-xdoc-1.0.jar",
1150+ "sha1": "538dce721987425bae72e55c318863ee4a412154"
1151+ },
1152+ {
1153+ "path": "org/apache/maven/doxia/doxia-module-xdoc/1.0/doxia-module-xdoc-1.0.pom",
1154+ "sha1": "3f97d4af3f734f0c71ce540b1fbf57708e2d76c8"
1155+ },
1156+ {
1157+ "path": "org/apache/maven/doxia/doxia-module-xdoc/1.4/doxia-module-xdoc-1.4.jar",
1158+ "sha1": "cf7d317034a3c8ab170076a4f82f6371ca5e6791"
1159+ },
1160+ {
1161+ "path": "org/apache/maven/doxia/doxia-module-xhtml/1.0/doxia-module-xhtml-1.0.jar",
1162+ "sha1": "237057eb966a49ad5e675f46b783880a0a703e86"
1163+ },
1164+ {
1165+ "path": "org/apache/maven/doxia/doxia-module-xhtml/1.0/doxia-module-xhtml-1.0.pom",
1166+ "sha1": "969aaeb5d46b76183b0bf3eacd3587cc44fd3d9e"
1167+ },
1168+ {
1169+ "path": "org/apache/maven/doxia/doxia-module-xhtml/1.4/doxia-module-xhtml-1.4.jar",
1170+ "sha1": "109b0b6b49fdd166b036c7fce93393fa98002c66"
1171+ },
1172+ {
1173+ "path": "org/apache/maven/doxia/doxia-modules/1.0/doxia-modules-1.0.pom",
1174+ "sha1": "0995eb509c335f35f0170182e9d64a76ddf4b02a"
1175+ },
1176+ {
1177+ "path": "org/apache/maven/doxia/doxia-sink-api/1.0-alpha-10/doxia-sink-api-1.0-alpha-10.pom",
1178+ "sha1": "80e28b4d518236464c97722dd9aa53092af181a7"
1179+ },
1180+ {
1181+ "path": "org/apache/maven/doxia/doxia-sink-api/1.0-alpha-7/doxia-sink-api-1.0-alpha-7.jar",
1182+ "sha1": "68464d54384c35119c70684d5d609b64635d1bbd"
1183+ },
1184+ {
1185+ "path": "org/apache/maven/doxia/doxia-sink-api/1.0-alpha-7/doxia-sink-api-1.0-alpha-7.pom",
1186+ "sha1": "d8e08f33563f684917311978da2ff03a9d0022ab"
1187+ },
1188+ {
1189+ "path": "org/apache/maven/doxia/doxia-sink-api/1.0/doxia-sink-api-1.0.jar",
1190+ "sha1": "13f502f2fb1d4e2db6f19352c85b83277084bb98"
1191+ },
1192+ {
1193+ "path": "org/apache/maven/doxia/doxia-sink-api/1.0/doxia-sink-api-1.0.pom",
1194+ "sha1": "5d842372fdb4c42d78824141f7be4c0d541c983f"
1195+ },
1196+ {
1197+ "path": "org/apache/maven/doxia/doxia-sink-api/1.4/doxia-sink-api-1.4.jar",
1198+ "sha1": "3cfed174cabb086426a9043da49a70526ff40d16"
1199+ },
1200+ {
1201+ "path": "org/apache/maven/doxia/doxia-site-renderer/1.0/doxia-site-renderer-1.0.jar",
1202+ "sha1": "c70e13ad9cb90f7cf88ceeb10eba2a85d0f9045f"
1203+ },
1204+ {
1205+ "path": "org/apache/maven/doxia/doxia-site-renderer/1.0/doxia-site-renderer-1.0.pom",
1206+ "sha1": "f2df20c85431398821cab8b1b65e3228df1f2ae5"
1207+ },
1208+ {
1209+ "path": "org/apache/maven/doxia/doxia-site-renderer/1.4/doxia-site-renderer-1.4.jar",
1210+ "sha1": "91acd32a131407bccefd2971c1103c5d16002da2"
1211+ },
1212+ {
1213+ "path": "org/apache/maven/doxia/doxia-sitetools/1.0/doxia-sitetools-1.0.pom",
1214+ "sha1": "adeed9a4562d79bbf2bbc22af664c4b7888ed49a"
1215+ },
1216+ {
1217+ "path": "org/apache/maven/doxia/doxia/1.0-alpha-10/doxia-1.0-alpha-10.pom",
1218+ "sha1": "219a2deff42bccd82cd3d5775a86b95ce48d3dd4"
1219+ },
1220+ {
1221+ "path": "org/apache/maven/doxia/doxia/1.0-alpha-7/doxia-1.0-alpha-7.pom",
1222+ "sha1": "fff8727b6ff366d624669f4b8dc4d4c7316bbb0c"
1223+ },
1224+ {
1225+ "path": "org/apache/maven/doxia/doxia/1.0/doxia-1.0.pom",
1226+ "sha1": "250d5a027daedc96539e3b3def7da7911feb6aae"
1227+ },
1228+ {
1229+ "path": "org/apache/maven/maven-aether-provider/3.0/maven-aether-provider-3.0.jar",
1230+ "sha1": "419f5eb63cf743a1a0f2a80ea5dde37fd1a4fec0"
1231+ },
1232+ {
1233+ "path": "org/apache/maven/maven-aether-provider/3.0/maven-aether-provider-3.0.pom",
1234+ "sha1": "a3e7fa0d4d0d26f901c919173681bab824c5588c"
1235+ },
1236+ {
1237+ "path": "org/apache/maven/maven-archiver/2.4.2/maven-archiver-2.4.2.jar",
1238+ "sha1": "ddcb393749701eb292a263a3500db69df39aef43"
1239+ },
1240+ {
1241+ "path": "org/apache/maven/maven-archiver/2.5/maven-archiver-2.5.jar",
1242+ "sha1": "c999ae305f22ecfc5a000dca12a39b9491778bd5"
1243+ },
1244+ {
1245+ "path": "org/apache/maven/maven-archiver/2.5/maven-archiver-2.5.pom",
1246+ "sha1": "a46a65782b96c7624c0ff64b50a91ba2935d84f6"
1247+ },
1248+ {
1249+ "path": "org/apache/maven/maven-artifact-manager/2.0.2/maven-artifact-manager-2.0.2.jar",
1250+ "sha1": "982eee8d0feb92587beb60874c731febc6d9ed9d"
1251+ },
1252+ {
1253+ "path": "org/apache/maven/maven-artifact-manager/2.0.2/maven-artifact-manager-2.0.2.pom",
1254+ "sha1": "157c24fb3ec09b9a693f88dc571fc17ed0669cca"
1255+ },
1256+ {
1257+ "path": "org/apache/maven/maven-artifact-manager/2.0.5/maven-artifact-manager-2.0.5.pom",
1258+ "sha1": "cc2c71211f52ada0389f3d2c9de16dd1429eccd7"
1259+ },
1260+ {
1261+ "path": "org/apache/maven/maven-artifact-manager/2.0.6/maven-artifact-manager-2.0.6.jar",
1262+ "sha1": "dc326c3a989c10618e09a7b77cadeff297591942"
1263+ },
1264+ {
1265+ "path": "org/apache/maven/maven-artifact-manager/2.0.6/maven-artifact-manager-2.0.6.pom",
1266+ "sha1": "8cb8b1dc4d9f7fbd90be4e9c8e9a1d353e28666c"
1267+ },
1268+ {
1269+ "path": "org/apache/maven/maven-artifact-manager/2.0.8/maven-artifact-manager-2.0.8.pom",
1270+ "sha1": "5c9b2820e6abe0c070c0dedfdacf642a85abf2e6"
1271+ },
1272+ {
1273+ "path": "org/apache/maven/maven-artifact-manager/2.0.9/maven-artifact-manager-2.0.9.jar",
1274+ "sha1": "53224a5254101fb9b6d561d5a53c6d0817036d94"
1275+ },
1276+ {
1277+ "path": "org/apache/maven/maven-artifact-manager/2.0.9/maven-artifact-manager-2.0.9.pom",
1278+ "sha1": "84c14dcd1d85eebccbba665f95057b5748f51d83"
1279+ },
1280+ {
1281+ "path": "org/apache/maven/maven-artifact-manager/2.2.0/maven-artifact-manager-2.2.0.pom",
1282+ "sha1": "91b2c4b9a4cb63846da595ff15df78ebc7f1b31f"
1283+ },
1284+ {
1285+ "path": "org/apache/maven/maven-artifact-manager/2.2.1/maven-artifact-manager-2.2.1.jar",
1286+ "sha1": "ec355b913c34d37080810f98e3f51abecbe1572b"
1287+ },
1288+ {
1289+ "path": "org/apache/maven/maven-artifact-manager/2.2.1/maven-artifact-manager-2.2.1.pom",
1290+ "sha1": "062f05a1fc0a40a6ea8fc8f0a1e9e2c02057ebaf"
1291+ },
1292+ {
1293+ "path": "org/apache/maven/maven-artifact/2.0.2/maven-artifact-2.0.2.pom",
1294+ "sha1": "a8b0aa4f932e948f979c872326a5ac9d7f4e123c"
1295+ },
1296+ {
1297+ "path": "org/apache/maven/maven-artifact/2.0.5/maven-artifact-2.0.5.pom",
1298+ "sha1": "d4b90628e1e33c3d2319aa3279f6498905fb7bd8"
1299+ },
1300+ {
1301+ "path": "org/apache/maven/maven-artifact/2.0.6/maven-artifact-2.0.6.jar",
1302+ "sha1": "fcbf6e26a6d26ecaa25c199b6f16bf168b2f28dc"
1303+ },
1304+ {
1305+ "path": "org/apache/maven/maven-artifact/2.0.6/maven-artifact-2.0.6.pom",
1306+ "sha1": "973c14299a051daf4e767cc60f15788b50c887f2"
1307+ },
1308+ {
1309+ "path": "org/apache/maven/maven-artifact/2.0.8/maven-artifact-2.0.8.pom",
1310+ "sha1": "351f42403e36c8661e8f0a8489bf537ba31ab17a"
1311+ },
1312+ {
1313+ "path": "org/apache/maven/maven-artifact/2.0.9/maven-artifact-2.0.9.jar",
1314+ "sha1": "66f0c8baa789fffdf54924cf395b26bbc2130435"
1315+ },
1316+ {
1317+ "path": "org/apache/maven/maven-artifact/2.0.9/maven-artifact-2.0.9.pom",
1318+ "sha1": "ffc6bb3eabd75a28d704e0431e7a44e7b4dff9bd"
1319+ },
1320+ {
1321+ "path": "org/apache/maven/maven-artifact/2.2.0/maven-artifact-2.2.0.pom",
1322+ "sha1": "adf024bc80dcc83893fc712b9fff6f8d1f224fc6"
1323+ },
1324+ {
1325+ "path": "org/apache/maven/maven-artifact/2.2.1/maven-artifact-2.2.1.jar",
1326+ "sha1": "23600f790d4dab2cb965419eaa982e3e84c428f8"
1327+ },
1328+ {
1329+ "path": "org/apache/maven/maven-artifact/2.2.1/maven-artifact-2.2.1.pom",
1330+ "sha1": "e37430ef3c3ee1d33817fdb45a0e538f49932c0a"
1331+ },
1332+ {
1333+ "path": "org/apache/maven/maven-artifact/3.0/maven-artifact-3.0.jar",
1334+ "sha1": "c29cfa43ce2ba09975a07c40d7241655d7c2fa29"
1335+ },
1336+ {
1337+ "path": "org/apache/maven/maven-artifact/3.0/maven-artifact-3.0.pom",
1338+ "sha1": "6823c7ad1a5557c2f96bd2fd312948513af8e524"
1339+ },
1340+ {
1341+ "path": "org/apache/maven/maven-artifact/3.3.9/maven-artifact-3.3.9.jar",
1342+ "sha1": "0f43afa184555fbc6e36b3334b17246c39b30f6e"
1343+ },
1344+ {
1345+ "path": "org/apache/maven/maven-artifact/3.3.9/maven-artifact-3.3.9.pom",
1346+ "sha1": "d1d1835d6f9f725841f6e0c8e40e00a19a4a1f9a"
1347+ },
1348+ {
1349+ "path": "org/apache/maven/maven-core/2.0.6/maven-core-2.0.6.jar",
1350+ "sha1": "33b78ed70029bfca9fadee5c8e7c9b27b9a39443"
1351+ },
1352+ {
1353+ "path": "org/apache/maven/maven-core/2.0.6/maven-core-2.0.6.pom",
1354+ "sha1": "b02365ee1822cff5839d9f85bc9b1cbfab9f5674"
1355+ },
1356+ {
1357+ "path": "org/apache/maven/maven-core/2.0.9/maven-core-2.0.9.jar",
1358+ "sha1": "e1003a0a66dae77515259c5e591ea1cfd73c2859"
1359+ },
1360+ {
1361+ "path": "org/apache/maven/maven-core/2.0.9/maven-core-2.0.9.pom",
1362+ "sha1": "25da75e747afa1c361f003aed72de2e48dd190a7"
1363+ },
1364+ {
1365+ "path": "org/apache/maven/maven-core/2.2.1/maven-core-2.2.1.jar",
1366+ "sha1": "6f488e461188496c62e161f32160b3465ce5901e"
1367+ },
1368+ {
1369+ "path": "org/apache/maven/maven-core/2.2.1/maven-core-2.2.1.pom",
1370+ "sha1": "c7312a507d519047be160bab5cbb56c07d0247a1"
1371+ },
1372+ {
1373+ "path": "org/apache/maven/maven-core/3.0/maven-core-3.0.jar",
1374+ "sha1": "73728ce32c9016c8bd05584301fa3ba3a6f5d20a"
1375+ },
1376+ {
1377+ "path": "org/apache/maven/maven-core/3.0/maven-core-3.0.pom",
1378+ "sha1": "3727542038487060064a4a14b74c7590d364c45b"
1379+ },
1380+ {
1381+ "path": "org/apache/maven/maven-error-diagnostics/2.0.6/maven-error-diagnostics-2.0.6.jar",
1382+ "sha1": "49f5380c07a79cd91ee09e0cb9063764f1f6525c"
1383+ },
1384+ {
1385+ "path": "org/apache/maven/maven-error-diagnostics/2.0.6/maven-error-diagnostics-2.0.6.pom",
1386+ "sha1": "31c0ce961dfc5b491e92ad0804dd48840dac7796"
1387+ },
1388+ {
1389+ "path": "org/apache/maven/maven-error-diagnostics/2.0.9/maven-error-diagnostics-2.0.9.jar",
1390+ "sha1": "46cc6b69beebc7bbf59c4f3842f72f2c1942e8e5"
1391+ },
1392+ {
1393+ "path": "org/apache/maven/maven-error-diagnostics/2.0.9/maven-error-diagnostics-2.0.9.pom",
1394+ "sha1": "dd562ddf84fc56b0693b42184a27d86d126ef02b"
1395+ },
1396+ {
1397+ "path": "org/apache/maven/maven-error-diagnostics/2.2.1/maven-error-diagnostics-2.2.1.jar",
1398+ "sha1": "e81bb342d7d172f23d108dc8fa979a1facdcde8e"
1399+ },
1400+ {
1401+ "path": "org/apache/maven/maven-error-diagnostics/2.2.1/maven-error-diagnostics-2.2.1.pom",
1402+ "sha1": "5074991d8d14a88e7c8bff294639a254d7ef387a"
1403+ },
1404+ {
1405+ "path": "org/apache/maven/maven-model-builder/3.0/maven-model-builder-3.0.jar",
1406+ "sha1": "bedc161a3b07a4bcd175b9428cdf18725d292b37"
1407+ },
1408+ {
1409+ "path": "org/apache/maven/maven-model-builder/3.0/maven-model-builder-3.0.pom",
1410+ "sha1": "e4b3e5ffec18728f099d8000e400ac763af2cc20"
1411+ },
1412+ {
1413+ "path": "org/apache/maven/maven-model/2.0.5/maven-model-2.0.5.pom",
1414+ "sha1": "0b5c0e9a116a812ef64831e5be5114bb4f518e58"
1415+ },
1416+ {
1417+ "path": "org/apache/maven/maven-model/2.0.6/maven-model-2.0.6.jar",
1418+ "sha1": "9649253c0e68a453f388e0a308c0653309f87807"
1419+ },
1420+ {
1421+ "path": "org/apache/maven/maven-model/2.0.6/maven-model-2.0.6.pom",
1422+ "sha1": "ea1dd9b8c7b1c3d2f0bdf314390ed7da7e463460"
1423+ },
1424+ {
1425+ "path": "org/apache/maven/maven-model/2.0.8/maven-model-2.0.8.pom",
1426+ "sha1": "6e51285e0830c3f05999ca4f3175ffc81f0be43b"
1427+ },
1428+ {
1429+ "path": "org/apache/maven/maven-model/2.0.9/maven-model-2.0.9.jar",
1430+ "sha1": "9fb844625928dd992842e180853fbb2b197c9a9d"
1431+ },
1432+ {
1433+ "path": "org/apache/maven/maven-model/2.0.9/maven-model-2.0.9.pom",
1434+ "sha1": "0978fe1857f847436fd3c454d25161e26fb2d5ec"
1435+ },
1436+ {
1437+ "path": "org/apache/maven/maven-model/2.2.0/maven-model-2.2.0.pom",
1438+ "sha1": "826351ed94e42205e27410676351e83486ec5bb2"
1439+ },
1440+ {
1441+ "path": "org/apache/maven/maven-model/2.2.1/maven-model-2.2.1.jar",
1442+ "sha1": "c0a1c17436ec3ff5a56207c031d82277b4250a29"
1443+ },
1444+ {
1445+ "path": "org/apache/maven/maven-model/2.2.1/maven-model-2.2.1.pom",
1446+ "sha1": "548a7e6354c1bc4a49dbec6bd17b4f8e9310201b"
1447+ },
1448+ {
1449+ "path": "org/apache/maven/maven-model/3.0/maven-model-3.0.jar",
1450+ "sha1": "24ce598c94a78341c42556fe9192dad6a2822405"
1451+ },
1452+ {
1453+ "path": "org/apache/maven/maven-model/3.0/maven-model-3.0.pom",
1454+ "sha1": "3aa89da7792286192b860c58841b3907364d33a8"
1455+ },
1456+ {
1457+ "path": "org/apache/maven/maven-model/3.3.9/maven-model-3.3.9.jar",
1458+ "sha1": "6efde8cbcb4de4c47f7e9c2a3ab2806022b5c70f"
1459+ },
1460+ {
1461+ "path": "org/apache/maven/maven-model/3.3.9/maven-model-3.3.9.pom",
1462+ "sha1": "4435603380715177bdda01d89c62ee69fd58dfc1"
1463+ },
1464+ {
1465+ "path": "org/apache/maven/maven-monitor/2.0.6/maven-monitor-2.0.6.jar",
1466+ "sha1": "ab682e67281bb025980181c83acbcad19042a342"
1467+ },
1468+ {
1469+ "path": "org/apache/maven/maven-monitor/2.0.6/maven-monitor-2.0.6.pom",
1470+ "sha1": "7ed6529eefa74ca263b65a7c20adf65af5bacdff"
1471+ },
1472+ {
1473+ "path": "org/apache/maven/maven-monitor/2.0.9/maven-monitor-2.0.9.jar",
1474+ "sha1": "ae55264ab9ffbbfdba08c8c7853bbe4a2dd32e8a"
1475+ },
1476+ {
1477+ "path": "org/apache/maven/maven-monitor/2.0.9/maven-monitor-2.0.9.pom",
1478+ "sha1": "872e92b9f9ebed4761ea469c2c385f2ffcd6a589"
1479+ },
1480+ {
1481+ "path": "org/apache/maven/maven-monitor/2.2.1/maven-monitor-2.2.1.jar",
1482+ "sha1": "afc57c3a1368cd34caccb638e00523701f398c20"
1483+ },
1484+ {
1485+ "path": "org/apache/maven/maven-monitor/2.2.1/maven-monitor-2.2.1.pom",
1486+ "sha1": "421fcf473a51d9695d8dfe4f8e977ae38087f2ae"
1487+ },
1488+ {
1489+ "path": "org/apache/maven/maven-parent/10/maven-parent-10.pom",
1490+ "sha1": "281aafa31dfa9544070448ea8f353434f53267e4"
1491+ },
1492+ {
1493+ "path": "org/apache/maven/maven-parent/11/maven-parent-11.pom",
1494+ "sha1": "4bb80173fa4979737840fda012af86f5beabf1bc"
1495+ },
1496+ {
1497+ "path": "org/apache/maven/maven-parent/13/maven-parent-13.pom",
1498+ "sha1": "743843d9973c083b7755e4a26a9c2ac369608ab5"
1499+ },
1500+ {
1501+ "path": "org/apache/maven/maven-parent/15/maven-parent-15.pom",
1502+ "sha1": "63d5a76e7f9d3c6d7870bde13438856ef5300336"
1503+ },
1504+ {
1505+ "path": "org/apache/maven/maven-parent/16/maven-parent-16.pom",
1506+ "sha1": "00fed95187c0c9bfd13c08a858cb6f00245a3fa9"
1507+ },
1508+ {
1509+ "path": "org/apache/maven/maven-parent/21/maven-parent-21.pom",
1510+ "sha1": "0ecebf1043d9c7bdd3d32a4184ad4ef9ad3ea744"
1511+ },
1512+ {
1513+ "path": "org/apache/maven/maven-parent/22/maven-parent-22.pom",
1514+ "sha1": "b8b69066f9f1c388a977669871df9b66782f751a"
1515+ },
1516+ {
1517+ "path": "org/apache/maven/maven-parent/23/maven-parent-23.pom",
1518+ "sha1": "f92ae4baba6616609a29f6287626ee3f50ed7d6e"
1519+ },
1520+ {
1521+ "path": "org/apache/maven/maven-parent/24/maven-parent-24.pom",
1522+ "sha1": "277cf98c25de4d7512aa6403635810c1018e82b0"
1523+ },
1524+ {
1525+ "path": "org/apache/maven/maven-parent/27/maven-parent-27.pom",
1526+ "sha1": "2672c73b6189bb9ff437ba94ac7f62975e1257dd"
1527+ },
1528+ {
1529+ "path": "org/apache/maven/maven-parent/30/maven-parent-30.pom",
1530+ "sha1": "c3b2d24677a5f694e069b8210e9793a88c9d28b5"
1531+ },
1532+ {
1533+ "path": "org/apache/maven/maven-parent/31/maven-parent-31.pom",
1534+ "sha1": "e773af8e851de63461222f3a26d37e4619431e03"
1535+ },
1536+ {
1537+ "path": "org/apache/maven/maven-parent/33/maven-parent-33.pom",
1538+ "sha1": "9dd736089b07fa56da1259c87a825a097ba0278c"
1539+ },
1540+ {
1541+ "path": "org/apache/maven/maven-parent/34/maven-parent-34.pom",
1542+ "sha1": "d03d96b2f4ee06300faa9731b0fa71feeec5a8ef"
1543+ },
1544+ {
1545+ "path": "org/apache/maven/maven-parent/5/maven-parent-5.pom",
1546+ "sha1": "5c1ab38decaca1ccd08294aeab135047ebbae00d"
1547+ },
1548+ {
1549+ "path": "org/apache/maven/maven-parent/6/maven-parent-6.pom",
1550+ "sha1": "e9c3dcf052c26ac7340fbd7a03a751e482855330"
1551+ },
1552+ {
1553+ "path": "org/apache/maven/maven-parent/7/maven-parent-7.pom",
1554+ "sha1": "2426103263cbaf5519433f16bd98cdc31870a10a"
1555+ },
1556+ {
1557+ "path": "org/apache/maven/maven-parent/8/maven-parent-8.pom",
1558+ "sha1": "6f92a85ec401422bfc6572759a0bab2ff5df525e"
1559+ },
1560+ {
1561+ "path": "org/apache/maven/maven-parent/9/maven-parent-9.pom",
1562+ "sha1": "a7d098bde368f683c2b51475a903a1e74b61ba32"
1563+ },
1564+ {
1565+ "path": "org/apache/maven/maven-plugin-api/2.0.6/maven-plugin-api-2.0.6.jar",
1566+ "sha1": "52b32fd980c8ead7a3858d057330bda1ace72d9d"
1567+ },
1568+ {
1569+ "path": "org/apache/maven/maven-plugin-api/2.0.6/maven-plugin-api-2.0.6.pom",
1570+ "sha1": "3af72b052dfefb73ecfae742613012b5396c8863"
1571+ },
1572+ {
1573+ "path": "org/apache/maven/maven-plugin-api/2.0.8/maven-plugin-api-2.0.8.pom",
1574+ "sha1": "df49abd86bcf9fd7a624562a7285049ebdd2f00e"
1575+ },
1576+ {
1577+ "path": "org/apache/maven/maven-plugin-api/2.0.9/maven-plugin-api-2.0.9.jar",
1578+ "sha1": "8b8cae9daa688fdb57995c6835a3e24475d554c0"
1579+ },
1580+ {
1581+ "path": "org/apache/maven/maven-plugin-api/2.0.9/maven-plugin-api-2.0.9.pom",
1582+ "sha1": "4f6c3d5d50d1e22dea74629b3c52e22b30b6cbbd"
1583+ },
1584+ {
1585+ "path": "org/apache/maven/maven-plugin-api/2.2.1/maven-plugin-api-2.2.1.jar",
1586+ "sha1": "d60c36b60f760e0b5b87dd0c6311f93a72dc4585"
1587+ },
1588+ {
1589+ "path": "org/apache/maven/maven-plugin-api/2.2.1/maven-plugin-api-2.2.1.pom",
1590+ "sha1": "29a30b7c8180601523293fd61b00fcb298d32230"
1591+ },
1592+ {
1593+ "path": "org/apache/maven/maven-plugin-api/3.0/maven-plugin-api-3.0.jar",
1594+ "sha1": "98f886f59bb0e69f8e86cdc082e69f2f4c13d648"
1595+ },
1596+ {
1597+ "path": "org/apache/maven/maven-plugin-api/3.0/maven-plugin-api-3.0.pom",
1598+ "sha1": "9627e130b4f516945f0db03119dbafb86f168026"
1599+ },
1600+ {
1601+ "path": "org/apache/maven/maven-plugin-api/3.3.9/maven-plugin-api-3.3.9.jar",
1602+ "sha1": "aa706ea7ca23776861b4eb2cea97cf345e791496"
1603+ },
1604+ {
1605+ "path": "org/apache/maven/maven-plugin-api/3.3.9/maven-plugin-api-3.3.9.pom",
1606+ "sha1": "9a2b35a6e916b9fea2a6afa9cd5238efd3d0c407"
1607+ },
1608+ {
1609+ "path": "org/apache/maven/maven-plugin-descriptor/2.0.6/maven-plugin-descriptor-2.0.6.jar",
1610+ "sha1": "30a00f4ef12d3901c4f842de99e9363e3743245f"
1611+ },
1612+ {
1613+ "path": "org/apache/maven/maven-plugin-descriptor/2.0.6/maven-plugin-descriptor-2.0.6.pom",
1614+ "sha1": "c03fb59f559651730a98907d4acf65e6ffb886d6"
1615+ },
1616+ {
1617+ "path": "org/apache/maven/maven-plugin-descriptor/2.0.9/maven-plugin-descriptor-2.0.9.jar",
1618+ "sha1": "10443d038cd57feb4a027e7dfe09bed0925a1953"
1619+ },
1620+ {
1621+ "path": "org/apache/maven/maven-plugin-descriptor/2.0.9/maven-plugin-descriptor-2.0.9.pom",
1622+ "sha1": "2752f80f21bd62796600c66859406a08a587c2d9"
1623+ },
1624+ {
1625+ "path": "org/apache/maven/maven-plugin-descriptor/2.2.1/maven-plugin-descriptor-2.2.1.jar",
1626+ "sha1": "68d20ae3c40c4664dc52be90338af796db7ffb32"
1627+ },
1628+ {
1629+ "path": "org/apache/maven/maven-plugin-descriptor/2.2.1/maven-plugin-descriptor-2.2.1.pom",
1630+ "sha1": "020c06240db8c2f9bcf8450414ef040becef16e0"
1631+ },
1632+ {
1633+ "path": "org/apache/maven/maven-plugin-parameter-documenter/2.0.6/maven-plugin-parameter-documenter-2.0.6.jar",
1634+ "sha1": "df6fa6c4adb313cb8937ffae96368bec1fd5d13d"
1635+ },
1636+ {
1637+ "path": "org/apache/maven/maven-plugin-parameter-documenter/2.0.6/maven-plugin-parameter-documenter-2.0.6.pom",
1638+ "sha1": "c6403fbdb781a3d47a771656054defe1173ce486"
1639+ },
1640+ {
1641+ "path": "org/apache/maven/maven-plugin-parameter-documenter/2.0.9/maven-plugin-parameter-documenter-2.0.9.jar",
1642+ "sha1": "f481e2677384f6a0ab96633567d736e70657e042"
1643+ },
1644+ {
1645+ "path": "org/apache/maven/maven-plugin-parameter-documenter/2.0.9/maven-plugin-parameter-documenter-2.0.9.pom",
1646+ "sha1": "a575e74bbf8402a2371034d3a128d214c4cee060"
1647+ },
1648+ {
1649+ "path": "org/apache/maven/maven-plugin-parameter-documenter/2.2.1/maven-plugin-parameter-documenter-2.2.1.jar",
1650+ "sha1": "1a117baac49437fc5a6fcd9f18f779e6bad4207e"
1651+ },
1652+ {
1653+ "path": "org/apache/maven/maven-plugin-parameter-documenter/2.2.1/maven-plugin-parameter-documenter-2.2.1.pom",
1654+ "sha1": "8eb54f97405512e83f680f29ef6163f5ef082acb"
1655+ },
1656+ {
1657+ "path": "org/apache/maven/maven-plugin-registry/2.0.6/maven-plugin-registry-2.0.6.jar",
1658+ "sha1": "4242ec8629b4797387751379f57e72cb718aac7a"
1659+ },
1660+ {
1661+ "path": "org/apache/maven/maven-plugin-registry/2.0.6/maven-plugin-registry-2.0.6.pom",
1662+ "sha1": "2e13beea3b3511c6075c60384d9e7fad18efbcdf"
1663+ },
1664+ {
1665+ "path": "org/apache/maven/maven-plugin-registry/2.0.8/maven-plugin-registry-2.0.8.pom",
1666+ "sha1": "8f64ad448251c2c6007e609088bb7aa45ff337c5"
1667+ },
1668+ {
1669+ "path": "org/apache/maven/maven-plugin-registry/2.0.9/maven-plugin-registry-2.0.9.jar",
1670+ "sha1": "a7172a87a7cb901cf6df4df9fd89a3c2d3f8a770"
1671+ },
1672+ {
1673+ "path": "org/apache/maven/maven-plugin-registry/2.0.9/maven-plugin-registry-2.0.9.pom",
1674+ "sha1": "403ed44092f56e1ebab891f37c69d61936c5c4da"
1675+ },
1676+ {
1677+ "path": "org/apache/maven/maven-plugin-registry/2.2.0/maven-plugin-registry-2.2.0.pom",
1678+ "sha1": "a28f479f5a2334f4018fd6812a6da2652a11d858"
1679+ },
1680+ {
1681+ "path": "org/apache/maven/maven-plugin-registry/2.2.1/maven-plugin-registry-2.2.1.jar",
1682+ "sha1": "72a24b7775649af78f3986b5aa7eb354b9674cfd"
1683+ },
1684+ {
1685+ "path": "org/apache/maven/maven-plugin-registry/2.2.1/maven-plugin-registry-2.2.1.pom",
1686+ "sha1": "c3575ac9ad32638af33d88829453bdc902ea8711"
1687+ },
1688+ {
1689+ "path": "org/apache/maven/maven-profile/2.0.5/maven-profile-2.0.5.pom",
1690+ "sha1": "d16b97a0ac60bf526c8a727dfa549a43ac57e519"
1691+ },
1692+ {
1693+ "path": "org/apache/maven/maven-profile/2.0.6/maven-profile-2.0.6.jar",
1694+ "sha1": "f03cd3820d2b4d60b93ccd17a1c14e8eeef63f79"
1695+ },
1696+ {
1697+ "path": "org/apache/maven/maven-profile/2.0.6/maven-profile-2.0.6.pom",
1698+ "sha1": "12d0d8217e613b9cb487c1d1d0db744a4f588528"
1699+ },
1700+ {
1701+ "path": "org/apache/maven/maven-profile/2.0.8/maven-profile-2.0.8.pom",
1702+ "sha1": "34de742e38173bc6b4bc921ad79567c282f880ab"
1703+ },
1704+ {
1705+ "path": "org/apache/maven/maven-profile/2.0.9/maven-profile-2.0.9.jar",
1706+ "sha1": "0b9b02df9134bff9edb4f4e1624243d005895234"
1707+ },
1708+ {
1709+ "path": "org/apache/maven/maven-profile/2.0.9/maven-profile-2.0.9.pom",
1710+ "sha1": "616ca5d9ab345e415c6e3f5f75ea24a952690ac0"
1711+ },
1712+ {
1713+ "path": "org/apache/maven/maven-profile/2.2.0/maven-profile-2.2.0.pom",
1714+ "sha1": "740bce07af0b724e8e79e62493b537e190d14c1f"
1715+ },
1716+ {
1717+ "path": "org/apache/maven/maven-profile/2.2.1/maven-profile-2.2.1.jar",
1718+ "sha1": "3950071587027e5086e9c395574a60650c432738"
1719+ },
1720+ {
1721+ "path": "org/apache/maven/maven-profile/2.2.1/maven-profile-2.2.1.pom",
1722+ "sha1": "075b47a5262cae02c228137399b8247e50a43284"
1723+ },
1724+ {
1725+ "path": "org/apache/maven/maven-project/2.0.5/maven-project-2.0.5.pom",
1726+ "sha1": "f8e28bec122e2092e91660758ede22e1f78744ee"
1727+ },
1728+ {
1729+ "path": "org/apache/maven/maven-project/2.0.6/maven-project-2.0.6.jar",
1730+ "sha1": "c0df764cd8f5bac660bfa53fa97fdd53663ee308"
1731+ },
1732+ {
1733+ "path": "org/apache/maven/maven-project/2.0.6/maven-project-2.0.6.pom",
1734+ "sha1": "28e9f98ae3688d8831052283b2d65bd18295a7f5"
1735+ },
1736+ {
1737+ "path": "org/apache/maven/maven-project/2.0.8/maven-project-2.0.8.pom",
1738+ "sha1": "13398a071f2094acc11add38afc85f75a3faac33"
1739+ },
1740+ {
1741+ "path": "org/apache/maven/maven-project/2.0.9/maven-project-2.0.9.jar",
1742+ "sha1": "30ec37813df5a212888a1f3df0b27497ecef4ad8"
1743+ },
1744+ {
1745+ "path": "org/apache/maven/maven-project/2.0.9/maven-project-2.0.9.pom",
1746+ "sha1": "152cb93838c431848f31cd5a7a7a11b98c57135e"
1747+ },
1748+ {
1749+ "path": "org/apache/maven/maven-project/2.2.0/maven-project-2.2.0.pom",
1750+ "sha1": "bce50c677b7219221db29b87470b6ba605ef0d3f"
1751+ },
1752+ {
1753+ "path": "org/apache/maven/maven-project/2.2.1/maven-project-2.2.1.jar",
1754+ "sha1": "8239e98c16f641d55a4ad0e0bab0aee3aff8933f"
1755+ },
1756+ {
1757+ "path": "org/apache/maven/maven-project/2.2.1/maven-project-2.2.1.pom",
1758+ "sha1": "d96e4545b4700ac177430b5189c3f2aa54f62ca1"
1759+ },
1760+ {
1761+ "path": "org/apache/maven/maven-repository-metadata/2.0.2/maven-repository-metadata-2.0.2.pom",
1762+ "sha1": "f731304626897c68836461f0df5134f26aeddcf1"
1763+ },
1764+ {
1765+ "path": "org/apache/maven/maven-repository-metadata/2.0.5/maven-repository-metadata-2.0.5.pom",
1766+ "sha1": "64b711de2206859a37333e015c24451546278123"
1767+ },
1768+ {
1769+ "path": "org/apache/maven/maven-repository-metadata/2.0.6/maven-repository-metadata-2.0.6.jar",
1770+ "sha1": "ae64379396d2eba33616ce1e0a458c3a744b317b"
1771+ },
1772+ {
1773+ "path": "org/apache/maven/maven-repository-metadata/2.0.6/maven-repository-metadata-2.0.6.pom",
1774+ "sha1": "bdcd11054562df6124286aaf252ae8f256879e26"
1775+ },
1776+ {
1777+ "path": "org/apache/maven/maven-repository-metadata/2.0.8/maven-repository-metadata-2.0.8.pom",
1778+ "sha1": "741cf565a37d838eb7bebbb3d38a8293835b6cd5"
1779+ },
1780+ {
1781+ "path": "org/apache/maven/maven-repository-metadata/2.0.9/maven-repository-metadata-2.0.9.jar",
1782+ "sha1": "dd79022a827b1d577865d5c97f8ad0c7d6b067b7"
1783+ },
1784+ {
1785+ "path": "org/apache/maven/maven-repository-metadata/2.0.9/maven-repository-metadata-2.0.9.pom",
1786+ "sha1": "dc5dac36e8c773d8645a681b71b3d80a3e3b8916"
1787+ },
1788+ {
1789+ "path": "org/apache/maven/maven-repository-metadata/2.2.0/maven-repository-metadata-2.2.0.pom",
1790+ "sha1": "7805801e5b7d9eafeb3baf07e864650a62991192"
1791+ },
1792+ {
1793+ "path": "org/apache/maven/maven-repository-metadata/2.2.1/maven-repository-metadata-2.2.1.jar",
1794+ "sha1": "98f0c07fcf1eeb213bef8d9316a9935184084b06"
1795+ },
1796+ {
1797+ "path": "org/apache/maven/maven-repository-metadata/2.2.1/maven-repository-metadata-2.2.1.pom",
1798+ "sha1": "415f88d96ea04b0fcef38c50123da1ccc2be49d2"
1799+ },
1800+ {
1801+ "path": "org/apache/maven/maven-repository-metadata/3.0/maven-repository-metadata-3.0.jar",
1802+ "sha1": "e3c41f7565b1e189ff7a312796b9d2c470c09a8b"
1803+ },
1804+ {
1805+ "path": "org/apache/maven/maven-repository-metadata/3.0/maven-repository-metadata-3.0.pom",
1806+ "sha1": "5126010cefcb80ed5dc6eb066541b546dbdbc971"
1807+ },
1808+ {
1809+ "path": "org/apache/maven/maven-settings-builder/3.0/maven-settings-builder-3.0.jar",
1810+ "sha1": "08234c1bdf7a9a28c671b0abf11f8adaa66440cd"
1811+ },
1812+ {
1813+ "path": "org/apache/maven/maven-settings-builder/3.0/maven-settings-builder-3.0.pom",
1814+ "sha1": "69a41566b573bda12bd2bb7dcb64d30da834cb9c"
1815+ },
1816+ {
1817+ "path": "org/apache/maven/maven-settings/2.0.5/maven-settings-2.0.5.pom",
1818+ "sha1": "87aabc89ef7581c3e8119acf01280a701f446f37"
1819+ },
1820+ {
1821+ "path": "org/apache/maven/maven-settings/2.0.6/maven-settings-2.0.6.jar",
1822+ "sha1": "5da16cf9def50e3a352cd7e8923a49ebd72003b8"
1823+ },
1824+ {
1825+ "path": "org/apache/maven/maven-settings/2.0.6/maven-settings-2.0.6.pom",
1826+ "sha1": "6e8ca6b7fce58a28d2b73774fe277593af14d82a"
1827+ },
1828+ {
1829+ "path": "org/apache/maven/maven-settings/2.0.8/maven-settings-2.0.8.pom",
1830+ "sha1": "2516e8bf74885aef0561c2132b185d882253cb19"
1831+ },
1832+ {
1833+ "path": "org/apache/maven/maven-settings/2.0.9/maven-settings-2.0.9.jar",
1834+ "sha1": "ab8d338c00fab0db29af358ab0676c3c02d7329f"
1835+ },
1836+ {
1837+ "path": "org/apache/maven/maven-settings/2.0.9/maven-settings-2.0.9.pom",
1838+ "sha1": "f1fde243f26152cc66f7f1d6b4e3bb19d39d6847"
1839+ },
1840+ {
1841+ "path": "org/apache/maven/maven-settings/2.2.0/maven-settings-2.2.0.pom",
1842+ "sha1": "2cd4b74ac9ee7d8213fa8b4bb585c36e3dc1e17c"
1843+ },
1844+ {
1845+ "path": "org/apache/maven/maven-settings/2.2.1/maven-settings-2.2.1.jar",
1846+ "sha1": "2236ffe71fa5f78ce42b0f5fc22c54ed45f14294"
1847+ },
1848+ {
1849+ "path": "org/apache/maven/maven-settings/2.2.1/maven-settings-2.2.1.pom",
1850+ "sha1": "d54135b84370b3b0b70d84ffbb4ddf161c303d56"
1851+ },
1852+ {
1853+ "path": "org/apache/maven/maven-settings/3.0/maven-settings-3.0.jar",
1854+ "sha1": "8ee129adae535dd610f2dc952fddce68ac42fd86"
1855+ },
1856+ {
1857+ "path": "org/apache/maven/maven-settings/3.0/maven-settings-3.0.pom",
1858+ "sha1": "efc9c618ca5b82f76d1894977482069fe0e4565a"
1859+ },
1860+ {
1861+ "path": "org/apache/maven/maven-toolchain/2.2.1/maven-toolchain-2.2.1.jar",
1862+ "sha1": "0be589179cfbbad11e48572bf1a28e3490c7b197"
1863+ },
1864+ {
1865+ "path": "org/apache/maven/maven-toolchain/2.2.1/maven-toolchain-2.2.1.pom",
1866+ "sha1": "ef19c9782d233f4515cf83b4208dd04731ed8989"
1867+ },
1868+ {
1869+ "path": "org/apache/maven/maven/2.0.2/maven-2.0.2.pom",
1870+ "sha1": "816e22beec3ee5c4a344959625a824bb6202daeb"
1871+ },
1872+ {
1873+ "path": "org/apache/maven/maven/2.0.5/maven-2.0.5.pom",
1874+ "sha1": "9801e4423479367099ad4507c51c4f7f5b19bc6f"
1875+ },
1876+ {
1877+ "path": "org/apache/maven/maven/2.0.6/maven-2.0.6.pom",
1878+ "sha1": "1991be0ed3e1820e135201406d5acabf8c08d426"
1879+ },
1880+ {
1881+ "path": "org/apache/maven/maven/2.0.8/maven-2.0.8.pom",
1882+ "sha1": "0b6bdac7d11f0fc5c4c4bb0f336323f7b86cddc0"
1883+ },
1884+ {
1885+ "path": "org/apache/maven/maven/2.0.9/maven-2.0.9.pom",
1886+ "sha1": "696e3d1eaf254c63347613715faa31e5eecb282d"
1887+ },
1888+ {
1889+ "path": "org/apache/maven/maven/2.2.0/maven-2.2.0.pom",
1890+ "sha1": "c5bb0fda80306d0d27b3221d511c5032c95b27fa"
1891+ },
1892+ {
1893+ "path": "org/apache/maven/maven/2.2.1/maven-2.2.1.pom",
1894+ "sha1": "7bc311044fbacb404de025b76feefa3567f0e5d7"
1895+ },
1896+ {
1897+ "path": "org/apache/maven/maven/3.0/maven-3.0.pom",
1898+ "sha1": "30c961aaf964aadcc028102ebe03d1afff324ec0"
1899+ },
1900+ {
1901+ "path": "org/apache/maven/maven/3.3.9/maven-3.3.9.pom",
1902+ "sha1": "6e8c698e365e1a895770db9eec7bd3e544e1464f"
1903+ },
1904+ {
1905+ "path": "org/apache/maven/plugin-tools/maven-plugin-annotations/3.5.2/maven-plugin-annotations-3.5.2.jar",
1906+ "sha1": "958c81789d4cc52e7f83ede3168633c0b03ea2de"
1907+ },
1908+ {
1909+ "path": "org/apache/maven/plugin-tools/maven-plugin-annotations/3.5.2/maven-plugin-annotations-3.5.2.pom",
1910+ "sha1": "263f39d1cb915beaa94497d2b4b6ec94ca5b1291"
1911+ },
1912+ {
1913+ "path": "org/apache/maven/plugin-tools/maven-plugin-tools/3.5.2/maven-plugin-tools-3.5.2.pom",
1914+ "sha1": "7c1b14adca1eef5063248cb8078b160e48c3a969"
1915+ },
1916+ {
1917+ "path": "org/apache/maven/plugins/maven-antrun-plugin/1.3/maven-antrun-plugin-1.3.jar",
1918+ "sha1": "a1481166aa4a16c3a37e65f40847e238cc878709"
1919+ },
1920+ {
1921+ "path": "org/apache/maven/plugins/maven-antrun-plugin/1.3/maven-antrun-plugin-1.3.pom",
1922+ "sha1": "338231886cec6cd6853b3a3628b9fe8fc10c6eb5"
1923+ },
1924+ {
1925+ "path": "org/apache/maven/plugins/maven-assembly-plugin/2.2-beta-5/maven-assembly-plugin-2.2-beta-5.jar",
1926+ "sha1": "b1fd2e4dea47cb9c2858d26ad0aa608b802d34e2"
1927+ },
1928+ {
1929+ "path": "org/apache/maven/plugins/maven-assembly-plugin/2.2-beta-5/maven-assembly-plugin-2.2-beta-5.pom",
1930+ "sha1": "e7faf80b1d8086bd26dc2c67f4e0252b8d47df44"
1931+ },
1932+ {
1933+ "path": "org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.jar",
1934+ "sha1": "75653decaefa85ca8114ff3a4f869bb2ee6d605d"
1935+ },
1936+ {
1937+ "path": "org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom",
1938+ "sha1": "8571a1cd21bed4fe28656c3303526fa7d1e582ad"
1939+ },
1940+ {
1941+ "path": "org/apache/maven/plugins/maven-compiler-plugin/3.8.1/maven-compiler-plugin-3.8.1.jar",
1942+ "sha1": "be834db00dbace3d7fd08a6e0e96ab5e4af45f99"
1943+ },
1944+ {
1945+ "path": "org/apache/maven/plugins/maven-compiler-plugin/3.8.1/maven-compiler-plugin-3.8.1.pom",
1946+ "sha1": "96021d81e9ecaa27aadb861c681840a768ea502b"
1947+ },
1948+ {
1949+ "path": "org/apache/maven/plugins/maven-dependency-plugin/2.8/maven-dependency-plugin-2.8.jar",
1950+ "sha1": "04c8dedf3d9b2a3f45f3daa93e11ca547d2063ca"
1951+ },
1952+ {
1953+ "path": "org/apache/maven/plugins/maven-dependency-plugin/2.8/maven-dependency-plugin-2.8.pom",
1954+ "sha1": "df6ec1e4d0850f1b58c5432e7eb103e87fa197ec"
1955+ },
1956+ {
1957+ "path": "org/apache/maven/plugins/maven-deploy-plugin/2.8.2/maven-deploy-plugin-2.8.2.jar",
1958+ "sha1": "3c2d83ecd387e9843142ae92a0439792c1500319"
1959+ },
1960+ {
1961+ "path": "org/apache/maven/plugins/maven-deploy-plugin/2.8.2/maven-deploy-plugin-2.8.2.pom",
1962+ "sha1": "7feb36f26137084a8a8654d83efcbd8fb3d8a0a1"
1963+ },
1964+ {
1965+ "path": "org/apache/maven/plugins/maven-install-plugin/2.4/maven-install-plugin-2.4.jar",
1966+ "sha1": "9d1316166fe4c313f56276935e08df11f45267c2"
1967+ },
1968+ {
1969+ "path": "org/apache/maven/plugins/maven-install-plugin/2.4/maven-install-plugin-2.4.pom",
1970+ "sha1": "a94328f3fcee1cebefa3d1224caa0050682da487"
1971+ },
1972+ {
1973+ "path": "org/apache/maven/plugins/maven-jar-plugin/2.4/maven-jar-plugin-2.4.jar",
1974+ "sha1": "e3200bcf357b5c5e26df072d27df160546bb079a"
1975+ },
1976+ {
1977+ "path": "org/apache/maven/plugins/maven-jar-plugin/2.4/maven-jar-plugin-2.4.pom",
1978+ "sha1": "ae9d54d974e163f260f89ecea8ff6d55e4b0963e"
1979+ },
1980+ {
1981+ "path": "org/apache/maven/plugins/maven-plugins/12/maven-plugins-12.pom",
1982+ "sha1": "1adf3bec812d8db9c1f18303aa22325ec2fb61ca"
1983+ },
1984+ {
1985+ "path": "org/apache/maven/plugins/maven-plugins/16/maven-plugins-16.pom",
1986+ "sha1": "b5c0ca0bf4e73800f888cee77741bc1fa9c8ed78"
1987+ },
1988+ {
1989+ "path": "org/apache/maven/plugins/maven-plugins/22/maven-plugins-22.pom",
1990+ "sha1": "beff44ae4eff1e5c79c01972083cd11fa6982462"
1991+ },
1992+ {
1993+ "path": "org/apache/maven/plugins/maven-plugins/23/maven-plugins-23.pom",
1994+ "sha1": "d40d68ba1f88d8e9b0040f175a6ff41928abd5e7"
1995+ },
1996+ {
1997+ "path": "org/apache/maven/plugins/maven-plugins/24/maven-plugins-24.pom",
1998+ "sha1": "91e68408f2d1774c5f39c0c4cd56a8b83e47c67f"
1999+ },
2000+ {
2001+ "path": "org/apache/maven/plugins/maven-plugins/25/maven-plugins-25.pom",
2002+ "sha1": "8f4f05aaf87c858d2323b3a8fcf37d0fe00ecc75"
2003+ },
2004+ {
2005+ "path": "org/apache/maven/plugins/maven-plugins/33/maven-plugins-33.pom",
2006+ "sha1": "1492c1ec367964ea0a088d128d13b1df4529c8ae"
2007+ },
2008+ {
2009+ "path": "org/apache/maven/plugins/maven-plugins/34/maven-plugins-34.pom",
2010+ "sha1": "039027f0abac25deccfc21486550731fa5f55858"
2011+ },
2012+ {
2013+ "path": "org/apache/maven/plugins/maven-release-plugin/2.5.3/maven-release-plugin-2.5.3.jar",
2014+ "sha1": "4a85ece12021a247251b9a28cf4d88b2ee80a17d"
2015+ },
2016+ {
2017+ "path": "org/apache/maven/plugins/maven-release-plugin/2.5.3/maven-release-plugin-2.5.3.pom",
2018+ "sha1": "975a495019c29e2fd12cc81d83aa88b4eb14a0fe"
2019+ },
2020+ {
2021+ "path": "org/apache/maven/plugins/maven-resources-plugin/2.6/maven-resources-plugin-2.6.jar",
2022+ "sha1": "dd093ff6a4b680eae7ae83b5ab04310249fc6590"
2023+ },
2024+ {
2025+ "path": "org/apache/maven/plugins/maven-resources-plugin/2.6/maven-resources-plugin-2.6.pom",
2026+ "sha1": "5db5c3a879f31e8de7b580c79a52b245454c4620"
2027+ },
2028+ {
2029+ "path": "org/apache/maven/plugins/maven-shade-plugin/3.2.4/maven-shade-plugin-3.2.4.jar",
2030+ "sha1": "4cb43b86676649691a3945872998b5514ed40505"
2031+ },
2032+ {
2033+ "path": "org/apache/maven/plugins/maven-shade-plugin/3.2.4/maven-shade-plugin-3.2.4.pom",
2034+ "sha1": "619e08e6eddb99e43a0ae42821ac83571ce9f787"
2035+ },
2036+ {
2037+ "path": "org/apache/maven/plugins/maven-site-plugin/3.3/maven-site-plugin-3.3.jar",
2038+ "sha1": "77ba1752b1ac4c4339d6f11554800960a56a4ae1"
2039+ },
2040+ {
2041+ "path": "org/apache/maven/plugins/maven-site-plugin/3.3/maven-site-plugin-3.3.pom",
2042+ "sha1": "e790e7e93471cf9245706d76747f4653dd58c0e7"
2043+ },
2044+ {
2045+ "path": "org/apache/maven/plugins/maven-surefire-plugin/2.22.2/maven-surefire-plugin-2.22.2.jar",
2046+ "sha1": "63d1dd017bfecc64a7b68b964e39e8d9f8f11a14"
2047+ },
2048+ {
2049+ "path": "org/apache/maven/plugins/maven-surefire-plugin/2.22.2/maven-surefire-plugin-2.22.2.pom",
2050+ "sha1": "f0bfc47221f365d6812e6c4091227f6425268980"
2051+ },
2052+ {
2053+ "path": "org/apache/maven/release/maven-release-manager/2.5.3/maven-release-manager-2.5.3.jar",
2054+ "sha1": "65485d8c11cee5f06ef70615a7e0a516ee055f1a"
2055+ },
2056+ {
2057+ "path": "org/apache/maven/release/maven-release/2.5.3/maven-release-2.5.3.pom",
2058+ "sha1": "43ecfac1cf706ce9e60b8742c3ef36029158e61a"
2059+ },
2060+ {
2061+ "path": "org/apache/maven/reporting/maven-reporting-api/2.0.6/maven-reporting-api-2.0.6.jar",
2062+ "sha1": "29ec352c90968c345b628be6c40ddfb5ec7010a8"
2063+ },
2064+ {
2065+ "path": "org/apache/maven/reporting/maven-reporting-api/2.0.6/maven-reporting-api-2.0.6.pom",
2066+ "sha1": "8d8037467cc092dbaf1ca8b513172e2a893b5b9b"
2067+ },
2068+ {
2069+ "path": "org/apache/maven/reporting/maven-reporting-api/2.0.9/maven-reporting-api-2.0.9.pom",
2070+ "sha1": "bc210876e266e2f3153e96832cbdc5cd3ba53cba"
2071+ },
2072+ {
2073+ "path": "org/apache/maven/reporting/maven-reporting-api/3.0/maven-reporting-api-3.0.jar",
2074+ "sha1": "b2541dd07d08cd5eff9bd4554a2ad6a4198e2dfe"
2075+ },
2076+ {
2077+ "path": "org/apache/maven/reporting/maven-reporting-api/3.0/maven-reporting-api-3.0.pom",
2078+ "sha1": "eca7bd81ad86e6d8a978f37e1d077fee5c59d41e"
2079+ },
2080+ {
2081+ "path": "org/apache/maven/reporting/maven-reporting-exec/1.1/maven-reporting-exec-1.1.jar",
2082+ "sha1": "6e584f7a77d08716e703aae223809e22cbba3af7"
2083+ },
2084+ {
2085+ "path": "org/apache/maven/reporting/maven-reporting-impl/2.0.5/maven-reporting-impl-2.0.5.jar",
2086+ "sha1": "a9830b74eaa96dd67a89d82f13a735252cc1c725"
2087+ },
2088+ {
2089+ "path": "org/apache/maven/reporting/maven-reporting-impl/2.0.5/maven-reporting-impl-2.0.5.pom",
2090+ "sha1": "2308b1d114a8ee45bf4131806c02f26078646a72"
2091+ },
2092+ {
2093+ "path": "org/apache/maven/reporting/maven-reporting/2.0.6/maven-reporting-2.0.6.pom",
2094+ "sha1": "0257fe61312283ef58817edf197e9c90db0bba25"
2095+ },
2096+ {
2097+ "path": "org/apache/maven/reporting/maven-reporting/2.0.9/maven-reporting-2.0.9.pom",
2098+ "sha1": "92fc48457601be497488cc316bc3617326977a24"
2099+ },
2100+ {
2101+ "path": "org/apache/maven/scm/maven-scm-api/1.9.4/maven-scm-api-1.9.4.jar",
2102+ "sha1": "20007a3e71fda6824900856e63e552416de2b59d"
2103+ },
2104+ {
2105+ "path": "org/apache/maven/shared/file-management/1.2.1/file-management-1.2.1.jar",
2106+ "sha1": "8f98bcaa7fd3625a172fd3de10bba8c32b9820ea"
2107+ },
2108+ {
2109+ "path": "org/apache/maven/shared/file-management/1.2.1/file-management-1.2.1.pom",
2110+ "sha1": "9aacc3da37949502b89807f0df2e6529ef33da0c"
2111+ },
2112+ {
2113+ "path": "org/apache/maven/shared/maven-artifact-transfer/0.12.0/maven-artifact-transfer-0.12.0.jar",
2114+ "sha1": "b63d86f97cda1456dcbda78bf57de779c372addd"
2115+ },
2116+ {
2117+ "path": "org/apache/maven/shared/maven-artifact-transfer/0.12.0/maven-artifact-transfer-0.12.0.pom",
2118+ "sha1": "c3dbc60cf87e50311ccf0f7c87ee43681dfb2edc"
2119+ },
2120+ {
2121+ "path": "org/apache/maven/shared/maven-common-artifact-filters/1.4/maven-common-artifact-filters-1.4.jar",
2122+ "sha1": "de97ff2efd804f06c3698a914f2d55205742bcc4"
2123+ },
2124+ {
2125+ "path": "org/apache/maven/shared/maven-common-artifact-filters/1.4/maven-common-artifact-filters-1.4.pom",
2126+ "sha1": "40c60d137280b0583ebff4b80361cd2a28ea9c42"
2127+ },
2128+ {
2129+ "path": "org/apache/maven/shared/maven-common-artifact-filters/3.0.1/maven-common-artifact-filters-3.0.1.jar",
2130+ "sha1": "1a98d8e3d5610bb0abf09a7756195e8b2ed215e5"
2131+ },
2132+ {
2133+ "path": "org/apache/maven/shared/maven-common-artifact-filters/3.0.1/maven-common-artifact-filters-3.0.1.pom",
2134+ "sha1": "c6e96947d07fc8d9d02f60ebccfd6e8080201676"
2135+ },
2136+ {
2137+ "path": "org/apache/maven/shared/maven-dependency-analyzer/1.4/maven-dependency-analyzer-1.4.jar",
2138+ "sha1": "2b20e6f9bb568e37ae952063d41b7a6d935dadb9"
2139+ },
2140+ {
2141+ "path": "org/apache/maven/shared/maven-dependency-analyzer/1.4/maven-dependency-analyzer-1.4.pom",
2142+ "sha1": "c4d24829dcaa5f153f0d3108cfd1fe370a7583f7"
2143+ },
2144+ {
2145+ "path": "org/apache/maven/shared/maven-dependency-tree/2.1/maven-dependency-tree-2.1.jar",
2146+ "sha1": "29c4d6aeae519809b9af0607156bbdd174efb0bb"
2147+ },
2148+ {
2149+ "path": "org/apache/maven/shared/maven-dependency-tree/2.1/maven-dependency-tree-2.1.pom",
2150+ "sha1": "772a49d54d50ffe30dbfc50e86ed8318a188746c"
2151+ },
2152+ {
2153+ "path": "org/apache/maven/shared/maven-dependency-tree/3.0.1/maven-dependency-tree-3.0.1.jar",
2154+ "sha1": "e9ae9966f1d3a238004c8b15ca4fd0e03d405424"
2155+ },
2156+ {
2157+ "path": "org/apache/maven/shared/maven-dependency-tree/3.0.1/maven-dependency-tree-3.0.1.pom",
2158+ "sha1": "836669a016f1abbabc9a4776c4b76fa097f8a7d5"
2159+ },
2160+ {
2161+ "path": "org/apache/maven/shared/maven-doxia-tools/1.0.2/maven-doxia-tools-1.0.2.jar",
2162+ "sha1": "50453155feb184ee951c1b5444555637705cc32b"
2163+ },
2164+ {
2165+ "path": "org/apache/maven/shared/maven-doxia-tools/1.0.2/maven-doxia-tools-1.0.2.pom",
2166+ "sha1": "c6180757919a5a2e6bdd9f55ebb4adb6a6391ca3"
2167+ },
2168+ {
2169+ "path": "org/apache/maven/shared/maven-filtering/1.1/maven-filtering-1.1.jar",
2170+ "sha1": "c223ff4ef9e9b3b51b2c9310dda59527a4b85baf"
2171+ },
2172+ {
2173+ "path": "org/apache/maven/shared/maven-filtering/1.1/maven-filtering-1.1.pom",
2174+ "sha1": "58f9827f70cc29dd6aed2477b6384f14462f9576"
2175+ },
2176+ {
2177+ "path": "org/apache/maven/shared/maven-invoker/2.0.11/maven-invoker-2.0.11.jar",
2178+ "sha1": "9c71535d63b58390e5413218ed66012b18902847"
2179+ },
2180+ {
2181+ "path": "org/apache/maven/shared/maven-invoker/2.0.11/maven-invoker-2.0.11.pom",
2182+ "sha1": "c4a3df6dbe91d3a4303c77cd0ae6f77dc62f357b"
2183+ },
2184+ {
2185+ "path": "org/apache/maven/shared/maven-shared-components/10/maven-shared-components-10.pom",
2186+ "sha1": "a7dabc7cff7b683d810e33a63c85cbc630c3ebf3"
2187+ },
2188+ {
2189+ "path": "org/apache/maven/shared/maven-shared-components/11/maven-shared-components-11.pom",
2190+ "sha1": "f60de1679753378e91acd5e0b35c53ec1d3cdff7"
2191+ },
2192+ {
2193+ "path": "org/apache/maven/shared/maven-shared-components/12/maven-shared-components-12.pom",
2194+ "sha1": "bb93c9f13f4d000affb4425632ad00b2082049a3"
2195+ },
2196+ {
2197+ "path": "org/apache/maven/shared/maven-shared-components/15/maven-shared-components-15.pom",
2198+ "sha1": "ea4cecd1845e61708cd05f20d5d428a3d429e67c"
2199+ },
2200+ {
2201+ "path": "org/apache/maven/shared/maven-shared-components/17/maven-shared-components-17.pom",
2202+ "sha1": "9574bbf041ebae3dcf84c221d552dbeb01fe5b40"
2203+ },
2204+ {
2205+ "path": "org/apache/maven/shared/maven-shared-components/18/maven-shared-components-18.pom",
2206+ "sha1": "b9aa57e02b5452a9b6cc9147e40bb0b53a7c8009"
2207+ },
2208+ {
2209+ "path": "org/apache/maven/shared/maven-shared-components/19/maven-shared-components-19.pom",
2210+ "sha1": "650a49682d4c82f060c7cc8005f8734a5fd86af9"
2211+ },
2212+ {
2213+ "path": "org/apache/maven/shared/maven-shared-components/30/maven-shared-components-30.pom",
2214+ "sha1": "fed1e8496612f1fd3621e686a4cee4ea56d04cf9"
2215+ },
2216+ {
2217+ "path": "org/apache/maven/shared/maven-shared-components/33/maven-shared-components-33.pom",
2218+ "sha1": "3eb04765b707822b0b97eae2648b1054e21cbdb3"
2219+ },
2220+ {
2221+ "path": "org/apache/maven/shared/maven-shared-components/8/maven-shared-components-8.pom",
2222+ "sha1": "a6b88e9b00b5eea13069ce324293a85e427e57c6"
2223+ },
2224+ {
2225+ "path": "org/apache/maven/shared/maven-shared-incremental/1.1/maven-shared-incremental-1.1.jar",
2226+ "sha1": "9d017a7584086755445c0a260dd9a1e9eae161a5"
2227+ },
2228+ {
2229+ "path": "org/apache/maven/shared/maven-shared-incremental/1.1/maven-shared-incremental-1.1.pom",
2230+ "sha1": "c607b2c64c027151c440f27b5ec86e062b9e9953"
2231+ },
2232+ {
2233+ "path": "org/apache/maven/shared/maven-shared-io/1.1/maven-shared-io-1.1.jar",
2234+ "sha1": "02e1d57be05ecac7dbe56a3c73b113e98f22240f"
2235+ },
2236+ {
2237+ "path": "org/apache/maven/shared/maven-shared-io/1.1/maven-shared-io-1.1.pom",
2238+ "sha1": "031970802f3b9937e43a82ff11518e02a51669dc"
2239+ },
2240+ {
2241+ "path": "org/apache/maven/shared/maven-shared-utils/0.1/maven-shared-utils-0.1.pom",
2242+ "sha1": "c638aa76e8eb374e14c4a3d25f66f36454645a54"
2243+ },
2244+ {
2245+ "path": "org/apache/maven/shared/maven-shared-utils/3.1.0/maven-shared-utils-3.1.0.jar",
2246+ "sha1": "78d8798fe84d5e095577221d299e9a3c8e696bca"
2247+ },
2248+ {
2249+ "path": "org/apache/maven/shared/maven-shared-utils/3.1.0/maven-shared-utils-3.1.0.pom",
2250+ "sha1": "96d533d4ae5c8ae5abe3f2e04fea554e2b03fd99"
2251+ },
2252+ {
2253+ "path": "org/apache/maven/shared/maven-shared-utils/3.2.1/maven-shared-utils-3.2.1.jar",
2254+ "sha1": "08dd4dfb1d2d8b6969f6462790f82670bcd35ce2"
2255+ },
2256+ {
2257+ "path": "org/apache/maven/shared/maven-shared-utils/3.2.1/maven-shared-utils-3.2.1.pom",
2258+ "sha1": "9347480fc0b3162e873c3a1f83af76ee1f909924"
2259+ },
2260+ {
2261+ "path": "org/apache/maven/surefire/maven-surefire-common/2.22.2/maven-surefire-common-2.22.2.jar",
2262+ "sha1": "d22aaa69c65e96cd9d87f779e45df76fb5040108"
2263+ },
2264+ {
2265+ "path": "org/apache/maven/surefire/maven-surefire-common/2.22.2/maven-surefire-common-2.22.2.pom",
2266+ "sha1": "7024a6391c6869c06e7b801c9553553884df2fdb"
2267+ },
2268+ {
2269+ "path": "org/apache/maven/surefire/surefire-api/2.22.2/surefire-api-2.22.2.jar",
2270+ "sha1": "273caddf446705ccceada91064e7266eb8517608"
2271+ },
2272+ {
2273+ "path": "org/apache/maven/surefire/surefire-api/2.22.2/surefire-api-2.22.2.pom",
2274+ "sha1": "49b34d166f30020a893551f058148e559779daf2"
2275+ },
2276+ {
2277+ "path": "org/apache/maven/surefire/surefire-booter/2.22.2/surefire-booter-2.22.2.jar",
2278+ "sha1": "84f8a93e76a7991f7f57d0e3905d8cf76176d3f5"
2279+ },
2280+ {
2281+ "path": "org/apache/maven/surefire/surefire-booter/2.22.2/surefire-booter-2.22.2.pom",
2282+ "sha1": "378a14fb78a3ba2d3efbb8cce8370937d65d39e3"
2283+ },
2284+ {
2285+ "path": "org/apache/maven/surefire/surefire-logger-api/2.22.2/surefire-logger-api-2.22.2.jar",
2286+ "sha1": "7c1513509a6f386711cfe21f50127a2641986163"
2287+ },
2288+ {
2289+ "path": "org/apache/maven/surefire/surefire-logger-api/2.22.2/surefire-logger-api-2.22.2.pom",
2290+ "sha1": "8170e8a3cd87c73fb8c97233b57d8ea4000dc8bf"
2291+ },
2292+ {
2293+ "path": "org/apache/maven/surefire/surefire/2.22.2/surefire-2.22.2.pom",
2294+ "sha1": "2bf172bb2ad3375d96a945775254a5d23f82612e"
2295+ },
2296+ {
2297+ "path": "org/apache/maven/wagon/wagon-provider-api/1.0-alpha-6/wagon-provider-api-1.0-alpha-6.jar",
2298+ "sha1": "b3c986c63fc873fbaef75ad4e57cd162fd5c9dd6"
2299+ },
2300+ {
2301+ "path": "org/apache/maven/wagon/wagon-provider-api/1.0-alpha-6/wagon-provider-api-1.0-alpha-6.pom",
2302+ "sha1": "1c1add559b9ed89168c2ae447481cfb63937ce2f"
2303+ },
2304+ {
2305+ "path": "org/apache/maven/wagon/wagon-provider-api/1.0/wagon-provider-api-1.0.jar",
2306+ "sha1": "12bcd211158c0c09b027d06b70371861398fedea"
2307+ },
2308+ {
2309+ "path": "org/apache/maven/wagon/wagon/1.0-alpha-6/wagon-1.0-alpha-6.pom",
2310+ "sha1": "69aa7db6cd9b32c6026dfb3d77d6a6865a2a9fc3"
2311+ },
2312+ {
2313+ "path": "org/apache/velocity/velocity/1.5/velocity-1.5.jar",
2314+ "sha1": "09f306baf7523ffc0e81a6353d08a584d254133b"
2315+ },
2316+ {
2317+ "path": "org/apache/velocity/velocity/1.5/velocity-1.5.pom",
2318+ "sha1": "106262b58f0f2b44cc0dbb3d0fa77105f28f5e38"
2319+ },
2320+ {
2321+ "path": "org/apache/xbean/xbean-reflect/3.4/xbean-reflect-3.4.pom",
2322+ "sha1": "5027123eb872a166f5205a5eb00d3ed186b63277"
2323+ },
2324+ {
2325+ "path": "org/apache/xbean/xbean/3.4/xbean-3.4.pom",
2326+ "sha1": "6b6d0d977f3fb41cfd097a350472baefd82713f5"
2327+ },
2328+ {
2329+ "path": "org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar",
2330+ "sha1": "fc9dff4bb36d627bdc553de77e1f17efd790876c"
2331+ },
2332+ {
2333+ "path": "org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.pom",
2334+ "sha1": "41f951c2aff248588037007e8f915467b9971a6f"
2335+ },
2336+ {
2337+ "path": "org/assertj/assertj-core/3.20.2/assertj-core-3.20.2.jar",
2338+ "sha1": "66f1f0ebd6db2b24e4a731979171da16ba919cd5"
2339+ },
2340+ {
2341+ "path": "org/assertj/assertj-core/3.20.2/assertj-core-3.20.2.pom",
2342+ "sha1": "38cead0af72d29e73c923fba590788c2f9a0bffd"
2343+ },
2344+ {
2345+ "path": "org/assertj/assertj-parent-pom/2.2.13/assertj-parent-pom-2.2.13.pom",
2346+ "sha1": "c75c29cf525c7ea9fc104ed740260cba02c7634b"
2347+ },
2348+ {
2349+ "path": "org/checkerframework/checker-compat-qual/2.5.2/checker-compat-qual-2.5.2.jar",
2350+ "sha1": "dc0b20906c9e4b9724af29d11604efa574066892"
2351+ },
2352+ {
2353+ "path": "org/checkerframework/checker-compat-qual/2.5.2/checker-compat-qual-2.5.2.pom",
2354+ "sha1": "055f6817b93fa72267c4a0aa47e06f0e826f0339"
2355+ },
2356+ {
2357+ "path": "org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar",
2358+ "sha1": "435dc33e3019c9f019e15f01aa111de9d6b2b79c"
2359+ },
2360+ {
2361+ "path": "org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.pom",
2362+ "sha1": "493796785b3c508c4c25e539321218511bd1c1ae"
2363+ },
2364+ {
2365+ "path": "org/checkerframework/checker-qual/2.5.2/checker-qual-2.5.2.jar",
2366+ "sha1": "cea74543d5904a30861a61b4643a5f2bb372efc4"
2367+ },
2368+ {
2369+ "path": "org/checkerframework/checker-qual/2.5.2/checker-qual-2.5.2.pom",
2370+ "sha1": "7cee753353b0fc94e0300ad3dbf155069260c4d7"
2371+ },
2372+ {
2373+ "path": "org/codehaus/mojo/animal-sniffer-annotations/1.17/animal-sniffer-annotations-1.17.jar",
2374+ "sha1": "f97ce6decaea32b36101e37979f8b647f00681fb"
2375+ },
2376+ {
2377+ "path": "org/codehaus/mojo/animal-sniffer-annotations/1.17/animal-sniffer-annotations-1.17.pom",
2378+ "sha1": "80948bd07c5db60753d8d5a9164b8b2272e0842a"
2379+ },
2380+ {
2381+ "path": "org/codehaus/mojo/animal-sniffer-annotations/1.18/animal-sniffer-annotations-1.18.pom",
2382+ "sha1": "82452242e8e2d0e058182cb01f29c3c30391dac3"
2383+ },
2384+ {
2385+ "path": "org/codehaus/mojo/animal-sniffer-parent/1.17/animal-sniffer-parent-1.17.pom",
2386+ "sha1": "eea4b805793494ebb025e5a9926ea3cf1ee8b34d"
2387+ },
2388+ {
2389+ "path": "org/codehaus/mojo/animal-sniffer-parent/1.18/animal-sniffer-parent-1.18.pom",
2390+ "sha1": "dd9080d0b2019e3cbb8b97dc7c057787062172f2"
2391+ },
2392+ {
2393+ "path": "org/codehaus/mojo/mojo-parent/40/mojo-parent-40.pom",
2394+ "sha1": "d2fa7c95447827e9bbcb8c60bd9484c51202732e"
2395+ },
2396+ {
2397+ "path": "org/codehaus/mojo/mojo-parent/50/mojo-parent-50.pom",
2398+ "sha1": "8caf7f67d94e762418df68f034c88b6f18433860"
2399+ },
2400+ {
2401+ "path": "org/codehaus/plexus/plexus-archiver/1.0/plexus-archiver-1.0.jar",
2402+ "sha1": "b564a05aeecd4d81d6b81f57a1d495fc8c0f497f"
2403+ },
2404+ {
2405+ "path": "org/codehaus/plexus/plexus-archiver/2.1/plexus-archiver-2.1.jar",
2406+ "sha1": "97853695be4bba3724512226c4d910fed733e608"
2407+ },
2408+ {
2409+ "path": "org/codehaus/plexus/plexus-archiver/2.1/plexus-archiver-2.1.pom",
2410+ "sha1": "8e63c83bf055cf0357669ca934f64c6bf27fc640"
2411+ },
2412+ {
2413+ "path": "org/codehaus/plexus/plexus-archiver/2.3/plexus-archiver-2.3.jar",
2414+ "sha1": "6abb3f7e89a76b9ef95db62f209a8cbb0c03fab2"
2415+ },
2416+ {
2417+ "path": "org/codehaus/plexus/plexus-archiver/2.3/plexus-archiver-2.3.pom",
2418+ "sha1": "a955cd43f140b2717beaf3e9d13bc8468c401eb4"
2419+ },
2420+ {
2421+ "path": "org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom",
2422+ "sha1": "6944ec0d0cab19adf167332f7197e045d64a577c"
2423+ },
2424+ {
2425+ "path": "org/codehaus/plexus/plexus-classworlds/1.2-alpha-9/plexus-classworlds-1.2-alpha-9.pom",
2426+ "sha1": "32be3692644bf86d1226e13e2a60b49a9fa49571"
2427+ },
2428+ {
2429+ "path": "org/codehaus/plexus/plexus-classworlds/2.2.2/plexus-classworlds-2.2.2.pom",
2430+ "sha1": "df1dfb0099c8759b378fe0af3b4a564d2c16aa18"
2431+ },
2432+ {
2433+ "path": "org/codehaus/plexus/plexus-classworlds/2.2.3/plexus-classworlds-2.2.3.jar",
2434+ "sha1": "93b34d7a40ed56fe33274480c5792b656d3697a9"
2435+ },
2436+ {
2437+ "path": "org/codehaus/plexus/plexus-classworlds/2.2.3/plexus-classworlds-2.2.3.pom",
2438+ "sha1": "068f7ac6a425f5e82bbbb5faef91e4b5d3d84f76"
2439+ },
2440+ {
2441+ "path": "org/codehaus/plexus/plexus-classworlds/2.5.2/plexus-classworlds-2.5.2.jar",
2442+ "sha1": "4abb111bfdace5b8167db4c0ef74644f3f88f142"
2443+ },
2444+ {
2445+ "path": "org/codehaus/plexus/plexus-classworlds/2.5.2/plexus-classworlds-2.5.2.pom",
2446+ "sha1": "a39bedbc3fa3652d3606821d7c21d80e900f57a0"
2447+ },
2448+ {
2449+ "path": "org/codehaus/plexus/plexus-compiler-api/2.8.4/plexus-compiler-api-2.8.4.jar",
2450+ "sha1": "ab13f02c237842b1d81b531fafd27f3c13585a37"
2451+ },
2452+ {
2453+ "path": "org/codehaus/plexus/plexus-compiler-api/2.8.4/plexus-compiler-api-2.8.4.pom",
2454+ "sha1": "be4194949f559462e78267207a99360274a58056"
2455+ },
2456+ {
2457+ "path": "org/codehaus/plexus/plexus-compiler-javac/2.8.4/plexus-compiler-javac-2.8.4.jar",
2458+ "sha1": "4a2c03bf7663dff8fd512cc1a7adecacf1a2249b"
2459+ },
2460+ {
2461+ "path": "org/codehaus/plexus/plexus-compiler-javac/2.8.4/plexus-compiler-javac-2.8.4.pom",
2462+ "sha1": "fecd511a1cd70f23ecee2cecc52b4d89124c114c"
2463+ },
2464+ {
2465+ "path": "org/codehaus/plexus/plexus-compiler-manager/2.8.4/plexus-compiler-manager-2.8.4.jar",
2466+ "sha1": "43b09c6b1831e962259634ac9ae2e6ac0467560e"
2467+ },
2468+ {
2469+ "path": "org/codehaus/plexus/plexus-compiler-manager/2.8.4/plexus-compiler-manager-2.8.4.pom",
2470+ "sha1": "578d6fba6c0b8a91884f3e710e051ad466d33425"
2471+ },
2472+ {
2473+ "path": "org/codehaus/plexus/plexus-compiler/2.8.4/plexus-compiler-2.8.4.pom",
2474+ "sha1": "0e54ac334bbea91bcb67325d78871c4082522f28"
2475+ },
2476+ {
2477+ "path": "org/codehaus/plexus/plexus-compilers/2.8.4/plexus-compilers-2.8.4.pom",
2478+ "sha1": "2ee8e7bcc9426c075fa4d0c415fb648ea8a9d701"
2479+ },
2480+ {
2481+ "path": "org/codehaus/plexus/plexus-component-annotations/1.5.4/plexus-component-annotations-1.5.4.pom",
2482+ "sha1": "52093f92fd7f82edf464f86c4f7220f9effc4bf2"
2483+ },
2484+ {
2485+ "path": "org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar",
2486+ "sha1": "c72f2660d0cbed24246ddb55d7fdc4f7374d2078"
2487+ },
2488+ {
2489+ "path": "org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.pom",
2490+ "sha1": "fd506865d5d083d8cef9fdbf525ad99fcc3416c1"
2491+ },
2492+ {
2493+ "path": "org/codehaus/plexus/plexus-component-annotations/1.7.1/plexus-component-annotations-1.7.1.jar",
2494+ "sha1": "862abca6deff0fff241a835a33d22559e9132069"
2495+ },
2496+ {
2497+ "path": "org/codehaus/plexus/plexus-component-annotations/1.7.1/plexus-component-annotations-1.7.1.pom",
2498+ "sha1": "e265daf1fcf56a67dd9bae3db80531a9717ccee4"
2499+ },
2500+ {
2501+ "path": "org/codehaus/plexus/plexus-component-annotations/2.0.0/plexus-component-annotations-2.0.0.jar",
2502+ "sha1": "6897b9fa8b67c900b52996f845e2d179eea13441"
2503+ },
2504+ {
2505+ "path": "org/codehaus/plexus/plexus-component-annotations/2.0.0/plexus-component-annotations-2.0.0.pom",
2506+ "sha1": "c273519bf9d766461c523facbf530ba18793bbe4"
2507+ },
2508+ {
2509+ "path": "org/codehaus/plexus/plexus-components/1.1.12/plexus-components-1.1.12.pom",
2510+ "sha1": "e7332a35914684bab5dd1718aea0202fa5a2bb0d"
2511+ },
2512+ {
2513+ "path": "org/codehaus/plexus/plexus-components/1.1.14/plexus-components-1.1.14.pom",
2514+ "sha1": "aed78d67ee20a5038741c7cc2a8124ae20c960ad"
2515+ },
2516+ {
2517+ "path": "org/codehaus/plexus/plexus-components/1.1.15/plexus-components-1.1.15.pom",
2518+ "sha1": "44366f11d5b9571c16829ae7f0a7f20e116f6260"
2519+ },
2520+ {
2521+ "path": "org/codehaus/plexus/plexus-components/1.1.18/plexus-components-1.1.18.pom",
2522+ "sha1": "41abf89f075e6b912a2ff728aa002e98591de425"
2523+ },
2524+ {
2525+ "path": "org/codehaus/plexus/plexus-components/1.1.19/plexus-components-1.1.19.pom",
2526+ "sha1": "2c0f4d3bcbcdd8f77521502d886681ed5af38a25"
2527+ },
2528+ {
2529+ "path": "org/codehaus/plexus/plexus-components/1.1.7/plexus-components-1.1.7.pom",
2530+ "sha1": "5fcdd5b77b86b603af118b70281f48539031a9f3"
2531+ },
2532+ {
2533+ "path": "org/codehaus/plexus/plexus-components/1.2/plexus-components-1.2.pom",
2534+ "sha1": "d0371336a8a00aa8ab99b332ac8eaf1665a9a3e5"
2535+ },
2536+ {
2537+ "path": "org/codehaus/plexus/plexus-components/1.3/plexus-components-1.3.pom",
2538+ "sha1": "979daf6b32bf4eb1fc8ff51689bf31731651a0c8"
2539+ },
2540+ {
2541+ "path": "org/codehaus/plexus/plexus-components/4.0/plexus-components-4.0.pom",
2542+ "sha1": "dcad998d9c45ca35212ac7efc49b729efce20395"
2543+ },
2544+ {
2545+ "path": "org/codehaus/plexus/plexus-container-default/1.0-alpha-20/plexus-container-default-1.0-alpha-20.pom",
2546+ "sha1": "911e3b5962b6485fd2fac68fa1af066f36388320"
2547+ },
2548+ {
2549+ "path": "org/codehaus/plexus/plexus-container-default/1.0-alpha-30/plexus-container-default-1.0-alpha-30.pom",
2550+ "sha1": "aa1efeb7ed05a3c5037cc194b9e8fbf97e52268a"
2551+ },
2552+ {
2553+ "path": "org/codehaus/plexus/plexus-container-default/1.0-alpha-8/plexus-container-default-1.0-alpha-8.pom",
2554+ "sha1": "3324c2065311b5cd636d3fe37353fe7558a6ec22"
2555+ },
2556+ {
2557+ "path": "org/codehaus/plexus/plexus-container-default/1.0-alpha-9-stable-1/plexus-container-default-1.0-alpha-9-stable-1.jar",
2558+ "sha1": "94aea3010e250a334d9dab7f591114cd6c767458"
2559+ },
2560+ {
2561+ "path": "org/codehaus/plexus/plexus-container-default/1.0-alpha-9-stable-1/plexus-container-default-1.0-alpha-9-stable-1.pom",
2562+ "sha1": "f557cb47f4594ac941d0edf08093a03ce15b51ba"
2563+ },
2564+ {
2565+ "path": "org/codehaus/plexus/plexus-container-default/1.0-alpha-9/plexus-container-default-1.0-alpha-9.jar",
2566+ "sha1": "50596183cd7b688d9d7b6d868a0193ca1a8a7b3d"
2567+ },
2568+ {
2569+ "path": "org/codehaus/plexus/plexus-container-default/1.0-alpha-9/plexus-container-default-1.0-alpha-9.pom",
2570+ "sha1": "d00c65ec36fb3cc8c755182a7ee52d3d80340179"
2571+ },
2572+ {
2573+ "path": "org/codehaus/plexus/plexus-container-default/1.5.5/plexus-container-default-1.5.5.pom",
2574+ "sha1": "f68a6d3761cfdfdf1e13ce2c18327c514acad611"
2575+ },
2576+ {
2577+ "path": "org/codehaus/plexus/plexus-containers/1.0-alpha-20/plexus-containers-1.0-alpha-20.pom",
2578+ "sha1": "5e436ba5a20b19e6b840f087e12e1c993b427de0"
2579+ },
2580+ {
2581+ "path": "org/codehaus/plexus/plexus-containers/1.0-alpha-30/plexus-containers-1.0-alpha-30.pom",
2582+ "sha1": "8b6330c46076c52825feb050aa27c550b24b4a17"
2583+ },
2584+ {
2585+ "path": "org/codehaus/plexus/plexus-containers/1.0.3/plexus-containers-1.0.3.pom",
2586+ "sha1": "e16f1c9b83cdeb142fc038dd0262c61121d58c4b"
2587+ },
2588+ {
2589+ "path": "org/codehaus/plexus/plexus-containers/1.5.4/plexus-containers-1.5.4.pom",
2590+ "sha1": "b9942b081e9903371eb0c8f5677d1d2564b575ca"
2591+ },
2592+ {
2593+ "path": "org/codehaus/plexus/plexus-containers/1.5.5/plexus-containers-1.5.5.pom",
2594+ "sha1": "cd786b660f8a4c1c520403a5fa04c7be45212b84"
2595+ },
2596+ {
2597+ "path": "org/codehaus/plexus/plexus-containers/1.7.1/plexus-containers-1.7.1.pom",
2598+ "sha1": "7ff4e431b5af8100be6e9fcd946ba7c532d890e2"
2599+ },
2600+ {
2601+ "path": "org/codehaus/plexus/plexus-containers/2.0.0/plexus-containers-2.0.0.pom",
2602+ "sha1": "47ae11db323292909afbcbd817f9cafda054000a"
2603+ },
2604+ {
2605+ "path": "org/codehaus/plexus/plexus-digest/1.0/plexus-digest-1.0.jar",
2606+ "sha1": "5f6a5a5140cd39e8c987cf6c31429d917b31166e"
2607+ },
2608+ {
2609+ "path": "org/codehaus/plexus/plexus-digest/1.0/plexus-digest-1.0.pom",
2610+ "sha1": "df5c2e55c9f30db34972661819437f1802128861"
2611+ },
2612+ {
2613+ "path": "org/codehaus/plexus/plexus-i18n/1.0-beta-7/plexus-i18n-1.0-beta-7.jar",
2614+ "sha1": "3690f10a668b3c7ac2ef563f14cfb6b2ba30ee57"
2615+ },
2616+ {
2617+ "path": "org/codehaus/plexus/plexus-i18n/1.0-beta-7/plexus-i18n-1.0-beta-7.pom",
2618+ "sha1": "5080cbaf0a98e413017ed074c845673c16546500"
2619+ },
2620+ {
2621+ "path": "org/codehaus/plexus/plexus-interactivity-api/1.0-alpha-4/plexus-interactivity-api-1.0-alpha-4.jar",
2622+ "sha1": "0a8f1178664a5457eef3f4531eb62f9505e1295f"
2623+ },
2624+ {
2625+ "path": "org/codehaus/plexus/plexus-interactivity-api/1.0-alpha-4/plexus-interactivity-api-1.0-alpha-4.pom",
2626+ "sha1": "1376ffcc4a8d46dee6c1a9096d0dcad3be01f838"
2627+ },
2628+ {
2629+ "path": "org/codehaus/plexus/plexus-interpolation/1.11/plexus-interpolation-1.11.jar",
2630+ "sha1": "ad9dddff6043194904ad1d2c00ff1d003c3915f7"
2631+ },
2632+ {
2633+ "path": "org/codehaus/plexus/plexus-interpolation/1.11/plexus-interpolation-1.11.pom",
2634+ "sha1": "f03da80999422b6cc4300735789be83e4498a3bc"
2635+ },
2636+ {
2637+ "path": "org/codehaus/plexus/plexus-interpolation/1.12/plexus-interpolation-1.12.pom",
2638+ "sha1": "101dd833f7186103b61a0281da38c95ae440eb63"
2639+ },
2640+ {
2641+ "path": "org/codehaus/plexus/plexus-interpolation/1.13/plexus-interpolation-1.13.jar",
2642+ "sha1": "1740038076cec1946fd28ed5ac5c1688f7cf7630"
2643+ },
2644+ {
2645+ "path": "org/codehaus/plexus/plexus-interpolation/1.13/plexus-interpolation-1.13.pom",
2646+ "sha1": "5003aac564f8ab42ceede81b114c520b48271873"
2647+ },
2648+ {
2649+ "path": "org/codehaus/plexus/plexus-interpolation/1.14/plexus-interpolation-1.14.jar",
2650+ "sha1": "c88dd864fe8b8256c25558ce7cd63be66ba07693"
2651+ },
2652+ {
2653+ "path": "org/codehaus/plexus/plexus-interpolation/1.14/plexus-interpolation-1.14.pom",
2654+ "sha1": "e296d45aff17c16ed268c5b9480214a0d92937ab"
2655+ },
2656+ {
2657+ "path": "org/codehaus/plexus/plexus-interpolation/1.15/plexus-interpolation-1.15.jar",
2658+ "sha1": "d682b4b8c1a92329d5b114a51794ef178168abbe"
2659+ },
2660+ {
2661+ "path": "org/codehaus/plexus/plexus-interpolation/1.15/plexus-interpolation-1.15.pom",
2662+ "sha1": "3dda3be2ada841f5ca3976a48281349a99f27e89"
2663+ },
2664+ {
2665+ "path": "org/codehaus/plexus/plexus-io/2.0.2/plexus-io-2.0.2.jar",
2666+ "sha1": "5d1890f1099242d6a1a6a46640eed931a96ef67f"
2667+ },
2668+ {
2669+ "path": "org/codehaus/plexus/plexus-io/2.0.2/plexus-io-2.0.2.pom",
2670+ "sha1": "d0ad15a280e5bf6c32388cbef26fd7d428fa1623"
2671+ },
2672+ {
2673+ "path": "org/codehaus/plexus/plexus-io/2.0.6/plexus-io-2.0.6.jar",
2674+ "sha1": "ae2ddfcb316ac045cd85792cbfea928b4cfd5b8d"
2675+ },
2676+ {
2677+ "path": "org/codehaus/plexus/plexus-io/2.0.6/plexus-io-2.0.6.pom",
2678+ "sha1": "80663ba325fc5477350b3e27af62b4879d6f5ca8"
2679+ },
2680+ {
2681+ "path": "org/codehaus/plexus/plexus-java/0.9.10/plexus-java-0.9.10.jar",
2682+ "sha1": "269ef3b88d500716f958a8e2b78561f34d50df80"
2683+ },
2684+ {
2685+ "path": "org/codehaus/plexus/plexus-java/0.9.10/plexus-java-0.9.10.pom",
2686+ "sha1": "65d0f66fc4b0adafe01c8b29a8bd692d0d62ba09"
2687+ },
2688+ {
2689+ "path": "org/codehaus/plexus/plexus-languages/0.9.10/plexus-languages-0.9.10.pom",
2690+ "sha1": "f7816d2ab70df6ff670bcfb8376d14238a63be72"
2691+ },
2692+ {
2693+ "path": "org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.pom",
2694+ "sha1": "a82e1ddd2d795616ac58d73ed246b8ec65326dfa"
2695+ },
2696+ {
2697+ "path": "org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom",
2698+ "sha1": "15492ecd00920daca9ec15f6acd695b626621e5b"
2699+ },
2700+ {
2701+ "path": "org/codehaus/plexus/plexus-utils/1.3/plexus-utils-1.3.pom",
2702+ "sha1": "050fadd040060c86cfd5d78ba95dab0cffcbcf5e"
2703+ },
2704+ {
2705+ "path": "org/codehaus/plexus/plexus-utils/1.4.1/plexus-utils-1.4.1.pom",
2706+ "sha1": "0a77530df5e881e55a4ffaea4b6bf33d57bc5b26"
2707+ },
2708+ {
2709+ "path": "org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom",
2710+ "sha1": "0bdc8a7fbce7d9007a93d289a029b43e1196d85c"
2711+ },
2712+ {
2713+ "path": "org/codehaus/plexus/plexus-utils/1.4.6/plexus-utils-1.4.6.pom",
2714+ "sha1": "a734ee9396d2ac09764cef74ebc56ef0339f6bd2"
2715+ },
2716+ {
2717+ "path": "org/codehaus/plexus/plexus-utils/1.5.1/plexus-utils-1.5.1.pom",
2718+ "sha1": "2a0b3470063440066d3b8a084340ce07dbdbfedc"
2719+ },
2720+ {
2721+ "path": "org/codehaus/plexus/plexus-utils/1.5.10/plexus-utils-1.5.10.jar",
2722+ "sha1": "f387a2faa309154d90b90cc049e44b7833a6c282"
2723+ },
2724+ {
2725+ "path": "org/codehaus/plexus/plexus-utils/1.5.15/plexus-utils-1.5.15.jar",
2726+ "sha1": "c689598ce1eb94c304817877ed15911099972526"
2727+ },
2728+ {
2729+ "path": "org/codehaus/plexus/plexus-utils/1.5.15/plexus-utils-1.5.15.pom",
2730+ "sha1": "b1f42bc7ebc5be3c0414f67fe2daf3b183acd74f"
2731+ },
2732+ {
2733+ "path": "org/codehaus/plexus/plexus-utils/1.5.5/plexus-utils-1.5.5.pom",
2734+ "sha1": "6d04eaae6db5f8d879332da294a46df0fd81450f"
2735+ },
2736+ {
2737+ "path": "org/codehaus/plexus/plexus-utils/1.5.6/plexus-utils-1.5.6.pom",
2738+ "sha1": "2df1a6c4e7b1849a10643a37a6f66b21d49bd643"
2739+ },
2740+ {
2741+ "path": "org/codehaus/plexus/plexus-utils/1.5.7/plexus-utils-1.5.7.pom",
2742+ "sha1": "38ae56ab5c035d5ebbfda0d3b418d3c3ea41d83d"
2743+ },
2744+ {
2745+ "path": "org/codehaus/plexus/plexus-utils/1.5.8/plexus-utils-1.5.8.pom",
2746+ "sha1": "7deaa90e5725075c9f9fb5a2cfbef75c86a5e5b5"
2747+ },
2748+ {
2749+ "path": "org/codehaus/plexus/plexus-utils/2.0.4/plexus-utils-2.0.4.jar",
2750+ "sha1": "1a363fa733fba4285967162f9a6ffe6fd356ec24"
2751+ },
2752+ {
2753+ "path": "org/codehaus/plexus/plexus-utils/2.0.4/plexus-utils-2.0.4.pom",
2754+ "sha1": "ffd8cee6475d101a5697091e1c18b0d08e3a8ff8"
2755+ },
2756+ {
2757+ "path": "org/codehaus/plexus/plexus-utils/2.0.5/plexus-utils-2.0.5.jar",
2758+ "sha1": "7841ba10ea46c9611ce702c3833ff9fccc8ae6eb"
2759+ },
2760+ {
2761+ "path": "org/codehaus/plexus/plexus-utils/2.0.5/plexus-utils-2.0.5.pom",
2762+ "sha1": "51785edd83de609389ba142c9516752a4246aefc"
2763+ },
2764+ {
2765+ "path": "org/codehaus/plexus/plexus-utils/2.1/plexus-utils-2.1.pom",
2766+ "sha1": "093c8fac63e60cc811aac811b8d36ffe2aa5401f"
2767+ },
2768+ {
2769+ "path": "org/codehaus/plexus/plexus-utils/3.0.10/plexus-utils-3.0.10.pom",
2770+ "sha1": "c70632156c3f19286424329d71e82b2026b90471"
2771+ },
2772+ {
2773+ "path": "org/codehaus/plexus/plexus-utils/3.0.15/plexus-utils-3.0.15.jar",
2774+ "sha1": "519b3f1fc84d3387c61a8c8e6235daf89aea4168"
2775+ },
2776+ {
2777+ "path": "org/codehaus/plexus/plexus-utils/3.0.17/plexus-utils-3.0.17.pom",
2778+ "sha1": "f2f5fa2f18718b54e0c488e9c40ca68c9e0cd190"
2779+ },
2780+ {
2781+ "path": "org/codehaus/plexus/plexus-utils/3.0.22/plexus-utils-3.0.22.jar",
2782+ "sha1": "764f26e0ab13a87c48fe55f525dfb6a133b7a92f"
2783+ },
2784+ {
2785+ "path": "org/codehaus/plexus/plexus-utils/3.0.22/plexus-utils-3.0.22.pom",
2786+ "sha1": "553c5a129da11f6d56a2599ad0b21649a6d6de08"
2787+ },
2788+ {
2789+ "path": "org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.jar",
2790+ "sha1": "3da9c286180a66aba197db8ffa7bbdc756c3e31f"
2791+ },
2792+ {
2793+ "path": "org/codehaus/plexus/plexus-utils/3.0.5/plexus-utils-3.0.5.pom",
2794+ "sha1": "880976a01d8f71ced7c8da841e571479bb7b6021"
2795+ },
2796+ {
2797+ "path": "org/codehaus/plexus/plexus-utils/3.0.8/plexus-utils-3.0.8.pom",
2798+ "sha1": "45a8cbe47c297155f2e2ef10c1b7b4707ab55fc6"
2799+ },
2800+ {
2801+ "path": "org/codehaus/plexus/plexus-utils/3.0.9/plexus-utils-3.0.9.jar",
2802+ "sha1": "48362e7b8a6edd68f8ff2e26bfb84ee370a5380b"
2803+ },
2804+ {
2805+ "path": "org/codehaus/plexus/plexus-utils/3.0.9/plexus-utils-3.0.9.pom",
2806+ "sha1": "259d8924d1f827ee49c7c5b3913f76b18d6055ca"
2807+ },
2808+ {
2809+ "path": "org/codehaus/plexus/plexus-utils/3.0/plexus-utils-3.0.jar",
2810+ "sha1": "d63aa0daf60d573bada235e2b4207617dcf24959"
2811+ },
2812+ {
2813+ "path": "org/codehaus/plexus/plexus-utils/3.0/plexus-utils-3.0.pom",
2814+ "sha1": "fe3d8457b0cf4e219fd8e3edad5054b8e38f17b0"
2815+ },
2816+ {
2817+ "path": "org/codehaus/plexus/plexus-utils/3.1.1/plexus-utils-3.1.1.pom",
2818+ "sha1": "9444be6c0e7197eccde066fc5ed8aaba968e9a16"
2819+ },
2820+ {
2821+ "path": "org/codehaus/plexus/plexus-utils/3.3.0/plexus-utils-3.3.0.jar",
2822+ "sha1": "cf43b5391de623b36fe066a21127baef82c64022"
2823+ },
2824+ {
2825+ "path": "org/codehaus/plexus/plexus-utils/3.3.0/plexus-utils-3.3.0.pom",
2826+ "sha1": "de5faec837d872a1712aa89242845216118a9405"
2827+ },
2828+ {
2829+ "path": "org/codehaus/plexus/plexus-velocity/1.1.7/plexus-velocity-1.1.7.jar",
2830+ "sha1": "1440fc2552d1405b1c2d380ef3b96c4d9c6dbd0b"
2831+ },
2832+ {
2833+ "path": "org/codehaus/plexus/plexus-velocity/1.1.7/plexus-velocity-1.1.7.pom",
2834+ "sha1": "659f8ef80ef0cc3d101e63535b9c5a39f7bc4b3e"
2835+ },
2836+ {
2837+ "path": "org/codehaus/plexus/plexus-velocity/1.1.8/plexus-velocity-1.1.8.jar",
2838+ "sha1": "d6b34818c82cd2e2f7bc75a2852d31283d154291"
2839+ },
2840+ {
2841+ "path": "org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom",
2842+ "sha1": "039c3f6a3cbe1f9e7b4a3309d9d7062b6e390fa7"
2843+ },
2844+ {
2845+ "path": "org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom",
2846+ "sha1": "4693d4512d50c5159bef1c49def1d2690a327c30"
2847+ },
2848+ {
2849+ "path": "org/codehaus/plexus/plexus/1.0.12/plexus-1.0.12.pom",
2850+ "sha1": "71d4361c71c7454a2626f3e18c789747256fe0b1"
2851+ },
2852+ {
2853+ "path": "org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom",
2854+ "sha1": "06f66b2f7d2eef1d805c11bca91c89984cda4137"
2855+ },
2856+ {
2857+ "path": "org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom",
2858+ "sha1": "9e7c8432829962afe796b32587c1bfa841a317d5"
2859+ },
2860+ {
2861+ "path": "org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom",
2862+ "sha1": "89d241b1e5ee6a72d3dd95d9eb90f635deebcdb2"
2863+ },
2864+ {
2865+ "path": "org/codehaus/plexus/plexus/2.0.2/plexus-2.0.2.pom",
2866+ "sha1": "b6c97d19090baa51e953fb782e3986b068fb450f"
2867+ },
2868+ {
2869+ "path": "org/codehaus/plexus/plexus/2.0.3/plexus-2.0.3.pom",
2870+ "sha1": "bf472ec56fe823f1b4b997fe5b9396490ae9b1dc"
2871+ },
2872+ {
2873+ "path": "org/codehaus/plexus/plexus/2.0.5/plexus-2.0.5.pom",
2874+ "sha1": "c37b8e9129d8860dfdea27da2c5407de7c6faba7"
2875+ },
2876+ {
2877+ "path": "org/codehaus/plexus/plexus/2.0.6/plexus-2.0.6.pom",
2878+ "sha1": "da193f47e5ce5a2cb85931851b3698e61cde8227"
2879+ },
2880+ {
2881+ "path": "org/codehaus/plexus/plexus/2.0.7/plexus-2.0.7.pom",
2882+ "sha1": "f6ee62f8157f273757b8ffda59714a6a279a174d"
2883+ },
2884+ {
2885+ "path": "org/codehaus/plexus/plexus/3.0.1/plexus-3.0.1.pom",
2886+ "sha1": "9ae573423303ba80844ed564756442d32b97cc33"
2887+ },
2888+ {
2889+ "path": "org/codehaus/plexus/plexus/3.1/plexus-3.1.pom",
2890+ "sha1": "b64de86ceaa4f0e4d8ccc44a26c562c6fb7fb230"
2891+ },
2892+ {
2893+ "path": "org/codehaus/plexus/plexus/3.2/plexus-3.2.pom",
2894+ "sha1": "521733c90c6fb160311e47b51f0471642b69f64f"
2895+ },
2896+ {
2897+ "path": "org/codehaus/plexus/plexus/3.3.1/plexus-3.3.1.pom",
2898+ "sha1": "f081c65405b2d5e403c9d57e791b23f613966322"
2899+ },
2900+ {
2901+ "path": "org/codehaus/plexus/plexus/3.3/plexus-3.3.pom",
2902+ "sha1": "70ab8436286998acce80e63fe75067a70cfe3e43"
2903+ },
2904+ {
2905+ "path": "org/codehaus/plexus/plexus/4.0/plexus-4.0.pom",
2906+ "sha1": "cdbb31ee91973d16e8f8b0bda51ed4211e7a9f57"
2907+ },
2908+ {
2909+ "path": "org/codehaus/plexus/plexus/5.1/plexus-5.1.pom",
2910+ "sha1": "2fca82e2eb5172f6a2909bea7accc733581a8c71"
2911+ },
2912+ {
2913+ "path": "org/eclipse/aether/aether-util/0.9.0.M2/aether-util-0.9.0.M2.jar",
2914+ "sha1": "b957089deb654647da320ad7507b0a4b5ce23813"
2915+ },
2916+ {
2917+ "path": "org/eclipse/aether/aether-util/0.9.0.M2/aether-util-0.9.0.M2.pom",
2918+ "sha1": "938d4a7468d46180927cd14ccec6a5accfc428af"
2919+ },
2920+ {
2921+ "path": "org/eclipse/aether/aether/0.9.0.M2/aether-0.9.0.M2.pom",
2922+ "sha1": "e44bcfab62cbf0ad4f15a47aa9cc48368db2dc6d"
2923+ },
2924+ {
2925+ "path": "org/eclipse/ee4j/project/1.0.2/project-1.0.2.pom",
2926+ "sha1": "5730bedee1faaeeb62b0afc4ed1c4571f87a8eb4"
2927+ },
2928+ {
2929+ "path": "org/eclipse/ee4j/project/1.0.5/project-1.0.5.pom",
2930+ "sha1": "d391c5ed15d8fb1dadba9c5d1017006d56c50332"
2931+ },
2932+ {
2933+ "path": "org/eclipse/jgit/org.eclipse.jgit-parent/5.2.1.201812262042-r/org.eclipse.jgit-parent-5.2.1.201812262042-r.pom",
2934+ "sha1": "71ef80c1389d9c47dfe995e03ad655a7294167a2"
2935+ },
2936+ {
2937+ "path": "org/eclipse/jgit/org.eclipse.jgit/5.2.1.201812262042-r/org.eclipse.jgit-5.2.1.201812262042-r.jar",
2938+ "sha1": "34914e63e1463e40ba40e2e28b0392993ea3b938"
2939+ },
2940+ {
2941+ "path": "org/eclipse/jgit/org.eclipse.jgit/5.2.1.201812262042-r/org.eclipse.jgit-5.2.1.201812262042-r.pom",
2942+ "sha1": "91190a4dd7ea339c080ce5b76221e5fceaab58d6"
2943+ },
2944+ {
2945+ "path": "org/eclipse/sisu/org.eclipse.sisu.inject/0.3.2/org.eclipse.sisu.inject-0.3.2.jar",
2946+ "sha1": "59044b92ec27cc6fda7a2d24b2cd6cec23f31d5b"
2947+ },
2948+ {
2949+ "path": "org/eclipse/sisu/org.eclipse.sisu.inject/0.3.2/org.eclipse.sisu.inject-0.3.2.pom",
2950+ "sha1": "41a7f34260adf84181f7bfaf512e5c0ddde5f417"
2951+ },
2952+ {
2953+ "path": "org/eclipse/sisu/org.eclipse.sisu.plexus/0.3.2/org.eclipse.sisu.plexus-0.3.2.jar",
2954+ "sha1": "cd84cb43788de23847eec2999070f64381bdb495"
2955+ },
2956+ {
2957+ "path": "org/eclipse/sisu/org.eclipse.sisu.plexus/0.3.2/org.eclipse.sisu.plexus-0.3.2.pom",
2958+ "sha1": "2b368076ccdce46590f97214bde1aa0f9413f282"
2959+ },
2960+ {
2961+ "path": "org/eclipse/sisu/sisu-inject/0.3.2/sisu-inject-0.3.2.pom",
2962+ "sha1": "1cfcf623633b3f1d270f38ada2805ec81aec9130"
2963+ },
2964+ {
2965+ "path": "org/eclipse/sisu/sisu-plexus/0.3.2/sisu-plexus-0.3.2.pom",
2966+ "sha1": "cfcccb1005e63760bb7dac857fcfe2bbe9a55414"
2967+ },
2968+ {
2969+ "path": "org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar",
2970+ "sha1": "42a25dc3219429f0e5d060061f71acb49bf010a0"
2971+ },
2972+ {
2973+ "path": "org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom",
2974+ "sha1": "872e413497b906e7c9fa85ccc96046c5d1ef7ece"
2975+ },
2976+ {
2977+ "path": "org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom",
2978+ "sha1": "80391bd32bfa4837a15215d5e9f07c60555c379a"
2979+ },
2980+ {
2981+ "path": "org/jacoco/jacoco-maven-plugin/0.8.7/jacoco-maven-plugin-0.8.7.jar",
2982+ "sha1": "3958dec701e6ae1d47c1264d3a74f1a70c35cdad"
2983+ },
2984+ {
2985+ "path": "org/jacoco/jacoco-maven-plugin/0.8.7/jacoco-maven-plugin-0.8.7.pom",
2986+ "sha1": "c742cce4f08c3d70c270fd2113ffccef1b7c8db9"
2987+ },
2988+ {
2989+ "path": "org/jacoco/org.jacoco.agent/0.8.7/org.jacoco.agent-0.8.7-runtime.jar",
2990+ "sha1": "37df187b76888101ecd745282e9cd1ad4ea508d6"
2991+ },
2992+ {
2993+ "path": "org/jacoco/org.jacoco.agent/0.8.7/org.jacoco.agent-0.8.7.pom",
2994+ "sha1": "ea782b5dd63854e0691c3e62a450af8474a907f9"
2995+ },
2996+ {
2997+ "path": "org/jacoco/org.jacoco.build/0.8.7/org.jacoco.build-0.8.7.pom",
2998+ "sha1": "492fd345ea752983327442fe383590995e40a7aa"
2999+ },
3000+ {
3001+ "path": "org/jacoco/org.jacoco.core/0.8.7/org.jacoco.core-0.8.7.jar",
3002+ "sha1": "2c2dc2b720a7fb33afcf4f45b05db2eb5b4ffa10"
3003+ },
3004+ {
3005+ "path": "org/jacoco/org.jacoco.core/0.8.7/org.jacoco.core-0.8.7.pom",
3006+ "sha1": "a26a78c73750f93915a98daac900c5e7a37e4494"
3007+ },
3008+ {
3009+ "path": "org/jacoco/org.jacoco.report/0.8.7/org.jacoco.report-0.8.7.jar",
3010+ "sha1": "be3926576212ef4cbf317fbadd0cc372cc205ab6"
3011+ },
3012+ {
3013+ "path": "org/jacoco/org.jacoco.report/0.8.7/org.jacoco.report-0.8.7.pom",
3014+ "sha1": "e54f4220d1b60811466439dbc463dfa126048d1c"
3015+ },
3016+ {
3017+ "path": "org/jboss/weld/weld-api-bom/1.0/weld-api-bom-1.0.pom",
3018+ "sha1": "efa278108d83f051152fb414e78e231d8ce5b38e"
3019+ },
3020+ {
3021+ "path": "org/jboss/weld/weld-api-parent/1.0/weld-api-parent-1.0.pom",
3022+ "sha1": "508700c6712082eece7e9e29a99286fd70593afa"
3023+ },
3024+ {
3025+ "path": "org/jboss/weld/weld-parent/6/weld-parent-6.pom",
3026+ "sha1": "a6f50e34ff79bc4a5761a35b71d89b07a1d051ec"
3027+ },
3028+ {
3029+ "path": "org/jdom/jdom/1.1/jdom-1.1.jar",
3030+ "sha1": "1d04c0f321ea337f3661cf7ede8f4c6f653a8fdd"
3031+ },
3032+ {
3033+ "path": "org/jdom/jdom2/2.0.6/jdom2-2.0.6.jar",
3034+ "sha1": "6f14738ec2e9dd0011e343717fa624a10f8aab64"
3035+ },
3036+ {
3037+ "path": "org/jdom/jdom2/2.0.6/jdom2-2.0.6.pom",
3038+ "sha1": "11e250d112bc9f2a0e1a595a5f6ecd2802af2691"
3039+ },
3040+ {
3041+ "path": "org/junit/junit-bom/5.7.1/junit-bom-5.7.1.pom",
3042+ "sha1": "ea517dcd1a0692cf193264d3e3ef0cc1a4a7b410"
3043+ },
3044+ {
3045+ "path": "org/junit/junit-bom/5.7.2/junit-bom-5.7.2.pom",
3046+ "sha1": "e8848369738c03e40af5507686216f9b8b44b6a3"
3047+ },
3048+ {
3049+ "path": "org/junit/jupiter/junit-jupiter-api/5.7.2/junit-jupiter-api-5.7.2.jar",
3050+ "sha1": "f4b4079732a9c537983324cfa4e46655f21d2c56"
3051+ },
3052+ {
3053+ "path": "org/junit/jupiter/junit-jupiter-api/5.7.2/junit-jupiter-api-5.7.2.pom",
3054+ "sha1": "e1d9f605ed666ba964fbd02e2a7ca6f8422b529f"
3055+ },
3056+ {
3057+ "path": "org/junit/jupiter/junit-jupiter-engine/5.7.2/junit-jupiter-engine-5.7.2.jar",
3058+ "sha1": "9415680a889f00b8205a094c5c487bc69dc7077d"
3059+ },
3060+ {
3061+ "path": "org/junit/jupiter/junit-jupiter-engine/5.7.2/junit-jupiter-engine-5.7.2.pom",
3062+ "sha1": "840cf93d83c2aa76bb8e70b99824bdc6dfde0220"
3063+ },
3064+ {
3065+ "path": "org/junit/jupiter/junit-jupiter-params/5.7.2/junit-jupiter-params-5.7.2.jar",
3066+ "sha1": "685f832f8c54dd40100f646d61aca88ed9545421"
3067+ },
3068+ {
3069+ "path": "org/junit/jupiter/junit-jupiter-params/5.7.2/junit-jupiter-params-5.7.2.pom",
3070+ "sha1": "80879379707b6c927355922113562afe77b3fcca"
3071+ },
3072+ {
3073+ "path": "org/junit/jupiter/junit-jupiter/5.7.2/junit-jupiter-5.7.2.jar",
3074+ "sha1": "62faa742964a9d8dab8fdb4a0eab7b01441c171f"
3075+ },
3076+ {
3077+ "path": "org/junit/jupiter/junit-jupiter/5.7.2/junit-jupiter-5.7.2.pom",
3078+ "sha1": "88fabd0e43c7d1669c64bb07337bbc3798deb12e"
3079+ },
3080+ {
3081+ "path": "org/junit/platform/junit-platform-commons/1.7.2/junit-platform-commons-1.7.2.jar",
3082+ "sha1": "34adfea6c13fc4a996cf38cdad80800ce850d198"
3083+ },
3084+ {
3085+ "path": "org/junit/platform/junit-platform-commons/1.7.2/junit-platform-commons-1.7.2.pom",
3086+ "sha1": "f3f9908126ecaa774d8d8b015e12612926aaebf3"
3087+ },
3088+ {
3089+ "path": "org/junit/platform/junit-platform-engine/1.7.2/junit-platform-engine-1.7.2.jar",
3090+ "sha1": "2573770b46b8a199ed5f6b0f96fb99e468bfe891"
3091+ },
3092+ {
3093+ "path": "org/junit/platform/junit-platform-engine/1.7.2/junit-platform-engine-1.7.2.pom",
3094+ "sha1": "8c35e134715c567e87b36506e71cd76ef35d2e99"
3095+ },
3096+ {
3097+ "path": "org/mortbay/jetty/jetty-util/6.1.25/jetty-util-6.1.25.jar",
3098+ "sha1": "5527b01ad9c4a12b4101f9ddca31c04ac4fe8614"
3099+ },
3100+ {
3101+ "path": "org/mortbay/jetty/jetty/6.1.25/jetty-6.1.25.jar",
3102+ "sha1": "b242826712e0e5146bf57f07394691cf8cb5f5cd"
3103+ },
3104+ {
3105+ "path": "org/mozilla/rhino/1.7.7.2/rhino-1.7.7.2.jar",
3106+ "sha1": "a7c4a9ba8b6922374580d71060ef71eafa994256"
3107+ },
3108+ {
3109+ "path": "org/mozilla/rhino/1.7.7.2/rhino-1.7.7.2.pom",
3110+ "sha1": "741bec7f31e2980262ebe466970a2a2053369269"
3111+ },
3112+ {
3113+ "path": "org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar",
3114+ "sha1": "28c11eb91f9b6d8e200631d46e20a7f407f2a046"
3115+ },
3116+ {
3117+ "path": "org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.pom",
3118+ "sha1": "b5c66f49b69c36797c1fb7f4ec57776f261303ad"
3119+ },
3120+ {
3121+ "path": "org/ow2/asm/asm-analysis/8.0/asm-analysis-8.0.jar",
3122+ "sha1": "57b12c6a9e14788f63ee3c6c0132fadcce1727d0"
3123+ },
3124+ {
3125+ "path": "org/ow2/asm/asm-analysis/8.0/asm-analysis-8.0.pom",
3126+ "sha1": "e9ef727d5390f9faefafa7bfab2fd4a18e1ebe49"
3127+ },
3128+ {
3129+ "path": "org/ow2/asm/asm-analysis/9.1/asm-analysis-9.1.jar",
3130+ "sha1": "4f61b83b81d8b659958f4bcc48907e93ecea55a0"
3131+ },
3132+ {
3133+ "path": "org/ow2/asm/asm-analysis/9.1/asm-analysis-9.1.pom",
3134+ "sha1": "e30004dc53274dc96d0b9c6a3ac06bdcf6d23d86"
3135+ },
3136+ {
3137+ "path": "org/ow2/asm/asm-commons/8.0/asm-commons-8.0.jar",
3138+ "sha1": "ea2231bdb3394bcca5989db7f7586f743829a9cb"
3139+ },
3140+ {
3141+ "path": "org/ow2/asm/asm-commons/8.0/asm-commons-8.0.pom",
3142+ "sha1": "92946423017f753ede6d4470a763c4eff4a0e2f6"
3143+ },
3144+ {
3145+ "path": "org/ow2/asm/asm-commons/9.1/asm-commons-9.1.jar",
3146+ "sha1": "8b971b182eb5cf100b9e8d4119152d83e00e0fdd"
3147+ },
3148+ {
3149+ "path": "org/ow2/asm/asm-commons/9.1/asm-commons-9.1.pom",
3150+ "sha1": "5914a98fed0e76a0ce92a75704cacaf2454ae90a"
3151+ },
3152+ {
3153+ "path": "org/ow2/asm/asm-tree/8.0/asm-tree-8.0.jar",
3154+ "sha1": "7b31ca94da9f57334a5aed79b40f2b88c5ee9f4f"
3155+ },
3156+ {
3157+ "path": "org/ow2/asm/asm-tree/8.0/asm-tree-8.0.pom",
3158+ "sha1": "e80355a497077d7a16a47c449dfdd83626b0bf9c"
3159+ },
3160+ {
3161+ "path": "org/ow2/asm/asm-tree/9.1/asm-tree-9.1.jar",
3162+ "sha1": "c333f2a855069cb8eb17a40a3eb8b1b67755d0eb"
3163+ },
3164+ {
3165+ "path": "org/ow2/asm/asm-tree/9.1/asm-tree-9.1.pom",
3166+ "sha1": "aeef4f505fe557517394dc29e404fba6ba98c428"
3167+ },
3168+ {
3169+ "path": "org/ow2/asm/asm-util/8.0/asm-util-8.0.jar",
3170+ "sha1": "b21996293fd49851ed9017cfde3191e49f77fbd0"
3171+ },
3172+ {
3173+ "path": "org/ow2/asm/asm-util/8.0/asm-util-8.0.pom",
3174+ "sha1": "83a3d02ed5354a1516e10251f3b3be247c934e87"
3175+ },
3176+ {
3177+ "path": "org/ow2/asm/asm/6.2/asm-6.2.jar",
3178+ "sha1": "1b6c4ff09ce03f3052429139c2a68e295cae6604"
3179+ },
3180+ {
3181+ "path": "org/ow2/asm/asm/6.2/asm-6.2.pom",
3182+ "sha1": "c995a570b9984647aa8557f26691f694c93f76af"
3183+ },
3184+ {
3185+ "path": "org/ow2/asm/asm/8.0/asm-8.0.jar",
3186+ "sha1": "d1a17d07c60e9e82c8b31b1d8f9ca98726418db4"
3187+ },
3188+ {
3189+ "path": "org/ow2/asm/asm/8.0/asm-8.0.pom",
3190+ "sha1": "9498cc1db19c6c8492581795ce3373af0978b105"
3191+ },
3192+ {
3193+ "path": "org/ow2/asm/asm/9.1/asm-9.1.jar",
3194+ "sha1": "a99500cf6eea30535eeac6be73899d048f8d12a8"
3195+ },
3196+ {
3197+ "path": "org/ow2/asm/asm/9.1/asm-9.1.pom",
3198+ "sha1": "927153d04a920d5f06a9a4aefd5f6be60726117d"
3199+ },
3200+ {
3201+ "path": "org/ow2/ow2/1.5/ow2-1.5.pom",
3202+ "sha1": "d8edc69335f4d9f95f511716fb689c86fb0ebaae"
3203+ },
3204+ {
3205+ "path": "org/slf4j/jcl-over-slf4j/1.5.6/jcl-over-slf4j-1.5.6.jar",
3206+ "sha1": "629680940b7dcb02c3904deb85992b462c42e272"
3207+ },
3208+ {
3209+ "path": "org/slf4j/jcl-over-slf4j/1.5.6/jcl-over-slf4j-1.5.6.pom",
3210+ "sha1": "8aa25adef55174f1436073e551953c2f74a5c71b"
3211+ },
3212+ {
3213+ "path": "org/slf4j/slf4j-api/1.5.6/slf4j-api-1.5.6.jar",
3214+ "sha1": "ec9b7142625dfa1dcaf22db99ecb7c555ffa714d"
3215+ },
3216+ {
3217+ "path": "org/slf4j/slf4j-api/1.5.6/slf4j-api-1.5.6.pom",
3218+ "sha1": "b79729ffc12292c0ec755db12360486066f6fd34"
3219+ },
3220+ {
3221+ "path": "org/slf4j/slf4j-api/1.7.2/slf4j-api-1.7.2.jar",
3222+ "sha1": "0081d61b7f33ebeab314e07de0cc596f8e858d97"
3223+ },
3224+ {
3225+ "path": "org/slf4j/slf4j-api/1.7.2/slf4j-api-1.7.2.pom",
3226+ "sha1": "3fceb45ce8f7a6f87f3f2077a24a3833d1ecb4c6"
3227+ },
3228+ {
3229+ "path": "org/slf4j/slf4j-api/1.7.31/slf4j-api-1.7.31.jar",
3230+ "sha1": "9545c9cb71de4c18d97a91e32ef0be6f3f6661b7"
3231+ },
3232+ {
3233+ "path": "org/slf4j/slf4j-api/1.7.31/slf4j-api-1.7.31.pom",
3234+ "sha1": "f81ceb107e2d2a5776c39dcb4064d5f60a25889b"
3235+ },
3236+ {
3237+ "path": "org/slf4j/slf4j-api/1.7.5/slf4j-api-1.7.5.jar",
3238+ "sha1": "6b262da268f8ad9eff941b25503a9198f0a0ac93"
3239+ },
3240+ {
3241+ "path": "org/slf4j/slf4j-api/1.7.5/slf4j-api-1.7.5.pom",
3242+ "sha1": "8bef62de94ecb16f574fadc01dcd3127ddb1a4da"
3243+ },
3244+ {
3245+ "path": "org/slf4j/slf4j-jdk14/1.5.6/slf4j-jdk14-1.5.6.jar",
3246+ "sha1": "cc383fbd07dd1826bbcba1b907bbdc0b5be627f1"
3247+ },
3248+ {
3249+ "path": "org/slf4j/slf4j-jdk14/1.5.6/slf4j-jdk14-1.5.6.pom",
3250+ "sha1": "cbc0f6b542435be20eba2fc698cf209e606ec1b4"
3251+ },
3252+ {
3253+ "path": "org/slf4j/slf4j-log4j12/1.7.31/slf4j-log4j12-1.7.31.jar",
3254+ "sha1": "77f6829fb450ba38bf0cbfdf3706bd180617d1b4"
3255+ },
3256+ {
3257+ "path": "org/slf4j/slf4j-log4j12/1.7.31/slf4j-log4j12-1.7.31.pom",
3258+ "sha1": "56a981ea1aacd2bd69ee5da16ea7c398ffd90520"
3259+ },
3260+ {
3261+ "path": "org/slf4j/slf4j-parent/1.5.6/slf4j-parent-1.5.6.pom",
3262+ "sha1": "7e94cd535680417391d54c1b1a14bcf9ed29a400"
3263+ },
3264+ {
3265+ "path": "org/slf4j/slf4j-parent/1.7.2/slf4j-parent-1.7.2.pom",
3266+ "sha1": "26c68730e36b29249e0c3bb70eba4a5dbaa4f76c"
3267+ },
3268+ {
3269+ "path": "org/slf4j/slf4j-parent/1.7.31/slf4j-parent-1.7.31.pom",
3270+ "sha1": "4ca9e443d3146affc616b84a584fa99c754b1dc8"
3271+ },
3272+ {
3273+ "path": "org/slf4j/slf4j-parent/1.7.5/slf4j-parent-1.7.5.pom",
3274+ "sha1": "2955681f952b108824dfb16ca366f36f3cef7861"
3275+ },
3276+ {
3277+ "path": "org/slf4j/slf4j-simple/1.7.31/slf4j-simple-1.7.31.jar",
3278+ "sha1": "cf5df9007f6fb85f04728eec1dd96de73533fec7"
3279+ },
3280+ {
3281+ "path": "org/slf4j/slf4j-simple/1.7.31/slf4j-simple-1.7.31.pom",
3282+ "sha1": "0149324b7bee90e50da892a4d415f5149ed5e840"
3283+ },
3284+ {
3285+ "path": "org/sonatype/aether/aether-api/1.7/aether-api-1.7.jar",
3286+ "sha1": "0c491a637ee6795143b6708ce5f112e6a9f548f4"
3287+ },
3288+ {
3289+ "path": "org/sonatype/aether/aether-api/1.7/aether-api-1.7.pom",
3290+ "sha1": "07d9331c480f8028c0f009f4b332ff5b18230003"
3291+ },
3292+ {
3293+ "path": "org/sonatype/aether/aether-impl/1.7/aether-impl-1.7.jar",
3294+ "sha1": "5cc1803eb7126f759d34007b74e6dc44e9a9fb08"
3295+ },
3296+ {
3297+ "path": "org/sonatype/aether/aether-impl/1.7/aether-impl-1.7.pom",
3298+ "sha1": "1f6352a67ee0e08fa1cac00e982cdc305d10ce67"
3299+ },
3300+ {
3301+ "path": "org/sonatype/aether/aether-parent/1.7/aether-parent-1.7.pom",
3302+ "sha1": "9272ca55ba8e2a1f03addfd1b698511d5122c646"
3303+ },
3304+ {
3305+ "path": "org/sonatype/aether/aether-spi/1.7/aether-spi-1.7.jar",
3306+ "sha1": "1ea472b28d9d891d353c0311593f5e2a0e73d4be"
3307+ },
3308+ {
3309+ "path": "org/sonatype/aether/aether-spi/1.7/aether-spi-1.7.pom",
3310+ "sha1": "0fdd424fc1f7acd9268c0ceb07fd7aceedb1019f"
3311+ },
3312+ {
3313+ "path": "org/sonatype/aether/aether-util/1.7/aether-util-1.7.jar",
3314+ "sha1": "38485c9c086c3c867c2dd5371909337bd056c492"
3315+ },
3316+ {
3317+ "path": "org/sonatype/aether/aether-util/1.7/aether-util-1.7.pom",
3318+ "sha1": "3bd750dbf22b2effa411117b7230694cc4095f3f"
3319+ },
3320+ {
3321+ "path": "org/sonatype/forge/forge-parent/10/forge-parent-10.pom",
3322+ "sha1": "c24dc843444f348100c19ebd51157e7a5f61bfe7"
3323+ },
3324+ {
3325+ "path": "org/sonatype/forge/forge-parent/3/forge-parent-3.pom",
3326+ "sha1": "fdc1f6eb65f750775acd57ff4371d5657ae2e6d3"
3327+ },
3328+ {
3329+ "path": "org/sonatype/forge/forge-parent/4/forge-parent-4.pom",
3330+ "sha1": "564f266ea9323e57e246f0fca8f04f596663fb86"
3331+ },
3332+ {
3333+ "path": "org/sonatype/forge/forge-parent/5/forge-parent-5.pom",
3334+ "sha1": "a557514263bbd4a6daef8f125ab80e78413292d3"
3335+ },
3336+ {
3337+ "path": "org/sonatype/forge/forge-parent/6/forge-parent-6.pom",
3338+ "sha1": "8726e91194a5442e05472854652602a3b599f27d"
3339+ },
3340+ {
3341+ "path": "org/sonatype/oss/oss-parent/5/oss-parent-5.pom",
3342+ "sha1": "3ae20880ad3d5da6b1caec19e3de7e70dd2dd762"
3343+ },
3344+ {
3345+ "path": "org/sonatype/oss/oss-parent/6/oss-parent-6.pom",
3346+ "sha1": "765c355ec09ad070065d9d12a9245bba5c689d96"
3347+ },
3348+ {
3349+ "path": "org/sonatype/oss/oss-parent/7/oss-parent-7.pom",
3350+ "sha1": "46b8a785b60a2767095b8611613b58577e96d4c9"
3351+ },
3352+ {
3353+ "path": "org/sonatype/oss/oss-parent/9/oss-parent-9.pom",
3354+ "sha1": "e5cdc4d23b86d79c436f16fed20853284e868f65"
3355+ },
3356+ {
3357+ "path": "org/sonatype/plexus/plexus-build-api/0.0.4/plexus-build-api-0.0.4.jar",
3358+ "sha1": "8fdcf45c2fad3052a51385fdfc79753d9124a1a7"
3359+ },
3360+ {
3361+ "path": "org/sonatype/plexus/plexus-build-api/0.0.4/plexus-build-api-0.0.4.pom",
3362+ "sha1": "df389a276b6c493bcea1937339b29145a7ce99bf"
3363+ },
3364+ {
3365+ "path": "org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar",
3366+ "sha1": "50ade46f23bb38cd984b4ec560c46223432aac38"
3367+ },
3368+ {
3369+ "path": "org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.pom",
3370+ "sha1": "8c0bee97c1badb926611bf82358e392fedc07764"
3371+ },
3372+ {
3373+ "path": "org/sonatype/plexus/plexus-sec-dispatcher/1.3/plexus-sec-dispatcher-1.3.jar",
3374+ "sha1": "dedc02034fb8fcd7615d66593228cb71709134b4"
3375+ },
3376+ {
3377+ "path": "org/sonatype/plexus/plexus-sec-dispatcher/1.3/plexus-sec-dispatcher-1.3.pom",
3378+ "sha1": "b953c3a84a7d3f2a7f606e18c07ee38fb6766e3d"
3379+ },
3380+ {
3381+ "path": "org/sonatype/sisu/inject/guice-bean/1.4.2/guice-bean-1.4.2.pom",
3382+ "sha1": "11c2c29c95aa9c9d636ac349b33b49de1190deaf"
3383+ },
3384+ {
3385+ "path": "org/sonatype/sisu/inject/guice-plexus/1.4.2/guice-plexus-1.4.2.pom",
3386+ "sha1": "9b167556a64cb79acea3a8dbf6c2f580e2699d2b"
3387+ },
3388+ {
3389+ "path": "org/sonatype/sisu/sisu-guice/2.1.7/sisu-guice-2.1.7-noaop.jar",
3390+ "sha1": "8cb56e976b8e0e7b23f2969c32bef7b830c6d6ed"
3391+ },
3392+ {
3393+ "path": "org/sonatype/sisu/sisu-guice/2.1.7/sisu-guice-2.1.7.pom",
3394+ "sha1": "f690b118b2c3ca4cf400a558e6d000a971fd8d98"
3395+ },
3396+ {
3397+ "path": "org/sonatype/sisu/sisu-inject-bean/1.4.2/sisu-inject-bean-1.4.2.jar",
3398+ "sha1": "5cf37202afbaae899d63dd51b46d173df650af1b"
3399+ },
3400+ {
3401+ "path": "org/sonatype/sisu/sisu-inject-bean/1.4.2/sisu-inject-bean-1.4.2.pom",
3402+ "sha1": "8b8bd0a19ec8218bb04e27aca13658605c9d7588"
3403+ },
3404+ {
3405+ "path": "org/sonatype/sisu/sisu-inject-plexus/1.4.2/sisu-inject-plexus-1.4.2.jar",
3406+ "sha1": "53d863ed4879d4a43ad7aee7bc63f935cc513353"
3407+ },
3408+ {
3409+ "path": "org/sonatype/sisu/sisu-inject-plexus/1.4.2/sisu-inject-plexus-1.4.2.pom",
3410+ "sha1": "3e27a576e375175ba275f21692d99a386d879405"
3411+ },
3412+ {
3413+ "path": "org/sonatype/sisu/sisu-inject/1.4.2/sisu-inject-1.4.2.pom",
3414+ "sha1": "780340415a1dc940f10ae38a7b32e84db28c95dd"
3415+ },
3416+ {
3417+ "path": "org/sonatype/sisu/sisu-parent/1.4.2/sisu-parent-1.4.2.pom",
3418+ "sha1": "11c9a4a343a22f80cfe4e9677d7b0679850e4196"
3419+ },
3420+ {
3421+ "path": "org/sonatype/spice/spice-parent/10/spice-parent-10.pom",
3422+ "sha1": "8e0e4ba87d63321333c26494698377b1204633a8"
3423+ },
3424+ {
3425+ "path": "org/sonatype/spice/spice-parent/12/spice-parent-12.pom",
3426+ "sha1": "e86b2d826f53093e27dc579bea3becbf1425d9ba"
3427+ },
3428+ {
3429+ "path": "org/sonatype/spice/spice-parent/16/spice-parent-16.pom",
3430+ "sha1": "aefd3135046b7c3f5835283bcc3b670fc46692b9"
3431+ },
3432+ {
3433+ "path": "org/sonatype/spice/spice-parent/17/spice-parent-17.pom",
3434+ "sha1": "7f500699ef371383492a4d6ee799b1a77ffd82cc"
3435+ },
3436+ {
3437+ "path": "org/vafer/jdependency/2.4.0/jdependency-2.4.0.jar",
3438+ "sha1": "78ca0c5e686bf4dede312f53ae2f3bacf9eb7638"
3439+ },
3440+ {
3441+ "path": "org/vafer/jdependency/2.4.0/jdependency-2.4.0.pom",
3442+ "sha1": "a671bc7bf898dd47a3b2df5ce2cffaaed4570e42"
3443+ },
3444+ {
3445+ "path": "org/yaml/snakeyaml/1.24/snakeyaml-1.24.pom",
3446+ "sha1": "605d93a1f7549eb22a18cb85dc8970bd4123e234"
3447+ },
3448+ {
3449+ "path": "org/yaml/snakeyaml/1.26/snakeyaml-1.26.pom",
3450+ "sha1": "ebf6b3e5c0a055d004fe639c22b6831c6e7554e5"
3451+ },
3452+ {
3453+ "path": "org/yaml/snakeyaml/1.27/snakeyaml-1.27.jar",
3454+ "sha1": "359d62567480b07a679dc643f82fc926b100eed5"
3455+ },
3456+ {
3457+ "path": "org/yaml/snakeyaml/1.27/snakeyaml-1.27.pom",
3458+ "sha1": "cedcc7f40ce3aa17b2498344e5e72fc2e9c11acb"
3459+ },
3460+ {
3461+ "path": "oro/oro/2.0.8/oro-2.0.8.jar",
3462+ "sha1": "5592374f834645c4ae250f4c9fbb314c9369d698"
3463+ },
3464+ {
3465+ "path": "oro/oro/2.0.8/oro-2.0.8.pom",
3466+ "sha1": "6d10956ccdb32138560928ba9501648e430c34bb"
3467+ },
3468+ {
3469+ "path": "xml-apis/xml-apis/1.0.b2/xml-apis-1.0.b2.jar",
3470+ "sha1": "3136ca936f64c9d68529f048c2618bd356bf85c9"
3471+ },
3472+ {
3473+ "path": "xml-apis/xml-apis/1.0.b2/xml-apis-1.0.b2.pom",
3474+ "sha1": "2289016f8b8f6a600ce45a199426fe0f6b2be4b0"
3475+ },
3476+ {
3477+ "path": "xml-apis/xml-apis/2.0.2/xml-apis-2.0.2.pom",
3478+ "sha1": "bf2e4baaea312f54f2934c6eb9bbde0a2a4afb07"
3479+ }
3480+ ],
3481+ "groupId": "org.openapitools.openapidiff",
3482+ "metas": [],
3483+ "name": "openapi-diff-parent-2.0.0-SNAPSHOT",
3484+ "remotes": {
3485+ "central": "https://repo.maven.apache.org/maven2"
3486+ },
3487+ "submodules": [
3488+ {
3489+ "artifactId": "openapi-diff-parent",
3490+ "groupId": "org.openapitools.openapidiff",
3491+ "name": "openapi-diff-parent-2.0.0-SNAPSHOT",
3492+ "path": "./",
3493+ "version": "2.0.0-SNAPSHOT"
3494+ },
3495+ {
3496+ "artifactId": "openapi-diff-core",
3497+ "groupId": "org.openapitools.openapidiff",
3498+ "name": "openapi-diff-core-2.0.0-SNAPSHOT",
3499+ "path": "./core",
3500+ "version": "2.0.0-SNAPSHOT"
3501+ },
3502+ {
3503+ "artifactId": "openapi-diff-cli",
3504+ "groupId": "org.openapitools.openapidiff",
3505+ "name": "openapi-diff-cli-2.0.0-SNAPSHOT",
3506+ "path": "./cli",
3507+ "version": "2.0.0-SNAPSHOT"
3508+ }
3509+ ],
3510+ "version": "2.0.0-SNAPSHOT"
3511+}
benchmarks/report.mdnew file+41
@@ -0,0 +1,41 @@
1+| | Typeable | Atlassian | OpenApi Tools | oasdiff | Bump.sh |
2+| -------------------------------------------------------------------------------------------------------------------------- | -------- | --------- | ------------- | ------- | ------- |
3+| [enum-anyof](./enum-anyof) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
4+| [id](./id) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
5+| [json/recursive](./json/recursive) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
6+| [maximum-lowered](./maximum-lowered) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
7+| [pathItem/operation/parameters/allowEmptyValue/reset](./pathItem/operation/parameters/allowEmptyValue/reset) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
8+| [pathItem/operation/parameters/allowEmptyValue/set](./pathItem/operation/parameters/allowEmptyValue/set) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
9+| [pathItem/operation/parameters/change](./pathItem/operation/parameters/change) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
10+| [pathItem/operation/parameters/required/false/add](./pathItem/operation/parameters/required/false/add) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
11+| [pathItem/operation/parameters/required/false/del](./pathItem/operation/parameters/required/false/del) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
12+| [pathItem/operation/parameters/required/reset](./pathItem/operation/parameters/required/reset) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
13+| [pathItem/operation/parameters/required/set](./pathItem/operation/parameters/required/set) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
14+| [pathItem/operation/parameters/required/true/add](./pathItem/operation/parameters/required/true/add) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
15+| [pathItem/operation/parameters/required/true/del](./pathItem/operation/parameters/required/true/del) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
16+| [pathItem/operation/requestBody/mediaTypeObject/add](./pathItem/operation/requestBody/mediaTypeObject/add) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
17+| [pathItem/operation/requestBody/mediaTypeObject/change](./pathItem/operation/requestBody/mediaTypeObject/change) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
18+| [pathItem/operation/requestBody/mediaTypeObject/del](./pathItem/operation/requestBody/mediaTypeObject/del) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
19+| [pathItem/operation/requestBody/required/reset](./pathItem/operation/requestBody/required/reset) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
20+| [pathItem/operation/requestBody/required/set](./pathItem/operation/requestBody/required/set) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
21+| [pathItem/operation/responses/add](./pathItem/operation/responses/add) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
22+| [pathItem/operation/responses/change/headers/mandatory/add](./pathItem/operation/responses/change/headers/mandatory/add) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
23+| [pathItem/operation/responses/change/headers/mandatory/del](./pathItem/operation/responses/change/headers/mandatory/del) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
24+| [pathItem/operation/responses/change/headers/optional/add](./pathItem/operation/responses/change/headers/optional/add) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
25+| [pathItem/operation/responses/change/headers/optional/del](./pathItem/operation/responses/change/headers/optional/del) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
26+| [pathItem/operation/responses/change/mediaTypeObject/add](./pathItem/operation/responses/change/mediaTypeObject/add) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
27+| [pathItem/operation/responses/change/mediaTypeObject/change](./pathItem/operation/responses/change/mediaTypeObject/change) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
28+| [pathItem/operation/responses/change/mediaTypeObject/del](./pathItem/operation/responses/change/mediaTypeObject/del) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
29+| [pathItem/operation/responses/del](./pathItem/operation/responses/del) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
30+| [prod/6159](./prod/6159) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
31+| [prod/enum](./prod/enum) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
32+| [prod/pure](./prod/pure) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
33+| [prod/with-latest](./prod/with-latest) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
34+| [property-removed](./property-removed) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
35+| [property-removed-additional](./property-removed-additional) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
36+| [property-required](./property-required) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
37+| [recursive](./recursive) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
38+| [security-scheme](./security-scheme) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
39+| [servers](./servers) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
40+| [type-changing](./type-changing) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
41+| [unguarded-recursive](./unguarded-recursive) | ✅❌ | ✅❌ | ✅❌ | ✅❌ | ✅❌ |
ci/policeman.nixnew file+4
@@ -0,0 +1,4 @@
1+{ sources ? import ../nix/sources.nix
2+, pkgs ? import sources.nixpkgs { }
3+}:
4+pkgs.haskellPackages.policeman
compaREST.cabalnew file+227
@@ -0,0 +1,227 @@
1+cabal-version: 2.4
2+name: compaREST
3+version: 0.1.0.1
4+synopsis: Compatibility checker for OpenAPI
5+description: Compatibility checker for OpenAPI.
6+license: MIT
7+license-file: LICENSE
8+author: Typeable
9+maintainer: compaREST@typeable.io
10+copyright: 2021 Typeable
11+category: Web
12+build-type: Simple
13+extra-doc-files: README.md
14+ CHANGELOG.md
15+tested-with: GHC == 9.6
16+extra-source-files: css/awsm.min.css
17+extra-source-files:
18+ test/golden/**/*.yaml
19+ test/golden/**/*.md
20+
21+common common-options
22+ ghc-options:
23+ -Weverything
24+ -Wno-implicit-prelude
25+ -Wno-missing-safe-haskell-mode
26+ -Wno-safe
27+ -Wno-prepositive-qualified-module
28+ -Wno-missing-import-lists
29+ -Wno-missing-kind-signatures
30+ -Wno-partial-fields
31+ -Wno-all-missed-specialisations
32+ -Wno-missing-local-signatures
33+ -Wno-unsafe
34+ -fconstraint-solver-iterations=0
35+ default-language: Haskell2010
36+ build-depends: base >= 4.12.0.0 && < 5
37+ , text
38+
39+
40+ default-extensions: ApplicativeDo
41+ , BangPatterns
42+ , ConstraintKinds
43+ , DataKinds
44+ , DeriveAnyClass
45+ , DeriveFoldable
46+ , DeriveFunctor
47+ , DeriveGeneric
48+ , DeriveTraversable
49+ , DerivingStrategies
50+ , DerivingVia
51+ , DuplicateRecordFields
52+ , EmptyDataDeriving
53+ , FlexibleContexts
54+ , FlexibleInstances
55+ , FunctionalDependencies
56+ , GADTs
57+ , GeneralizedNewtypeDeriving
58+ , LambdaCase
59+ , MultiParamTypeClasses
60+ , MultiWayIf
61+ , NamedFieldPuns
62+ , NumDecimals
63+ , OverloadedStrings
64+ , PatternSynonyms
65+ , PolyKinds
66+ , QuasiQuotes
67+ , RankNTypes
68+ , RecordWildCards
69+ , ScopedTypeVariables
70+ , StandaloneDeriving
71+ , TemplateHaskell
72+ , TupleSections
73+ , TypeApplications
74+ , TypeFamilies
75+ , TypeOperators
76+ , UndecidableInstances
77+ , ViewPatterns
78+ , QuantifiedConstraints
79+ , DefaultSignatures
80+
81+
82+library
83+ import: common-options
84+ build-depends:
85+ , pcre2
86+ , open-union
87+ , vector
88+ , unordered-containers
89+ , type-fun
90+ , typerep-map
91+ , tagged
92+ , scientific
93+ , pandoc-types
94+ , openapi3
95+ , lattices
96+ , insert-ordered-containers
97+ , http-media
98+ , hashable
99+ , free
100+ , containers
101+ , comonad
102+ , attoparsec
103+ , transformers
104+ , mtl
105+ , aeson
106+ , generic-data
107+ , doctemplates
108+ , file-embed
109+ , data-default
110+ , ordered-containers
111+ , bytestring
112+ hs-source-dirs: src
113+ exposed-modules: Data.OpenApi.Compare.Behavior
114+ , Data.OpenApi.Compare.Common
115+ , Data.OpenApi.Compare.Formula
116+ , Data.OpenApi.Compare.Memo
117+ , Data.OpenApi.Compare.Orphans
118+ , Data.OpenApi.Compare.Paths
119+ , Data.OpenApi.Compare.PathsPrefixTree
120+ , Data.OpenApi.Compare.References
121+ , Data.OpenApi.Compare.Report
122+ , Data.OpenApi.Compare.Report.Html.Template
123+ , Data.OpenApi.Compare.Report.Jet
124+ , Data.OpenApi.Compare.Run
125+ , Data.OpenApi.Compare.Subtree
126+ , Data.OpenApi.Compare.Validate.Header
127+ , Data.OpenApi.Compare.Validate.Link
128+ , Data.OpenApi.Compare.Validate.MediaTypeObject
129+ , Data.OpenApi.Compare.Validate.OAuth2Flows
130+ , Data.OpenApi.Compare.Validate.OpenApi
131+ , Data.OpenApi.Compare.Validate.Operation
132+ , Data.OpenApi.Compare.Validate.Param
133+ , Data.OpenApi.Compare.Validate.PathFragment
134+ , Data.OpenApi.Compare.Validate.Products
135+ , Data.OpenApi.Compare.Validate.RequestBody
136+ , Data.OpenApi.Compare.Validate.Responses
137+ , Data.OpenApi.Compare.Validate.Schema
138+ , Data.OpenApi.Compare.Validate.Schema.DNF
139+ , Data.OpenApi.Compare.Validate.Schema.Issues
140+ , Data.OpenApi.Compare.Validate.Schema.JsonFormula
141+ , Data.OpenApi.Compare.Validate.Schema.Partition
142+ , Data.OpenApi.Compare.Validate.Schema.Process
143+ , Data.OpenApi.Compare.Validate.Schema.Traced
144+ , Data.OpenApi.Compare.Validate.Schema.TypedJson
145+ , Data.OpenApi.Compare.Validate.SecurityRequirement
146+ , Data.OpenApi.Compare.Validate.SecurityScheme
147+ , Data.OpenApi.Compare.Validate.Server
148+ , Data.OpenApi.Compare.Validate.Sums
149+ other-modules: Data.HList
150+ , Data.OpenUnion.Extra
151+
152+executable compaREST
153+ import: common-options
154+ hs-source-dirs: app
155+ main-is: Main.hs
156+ build-depends:
157+ compaREST
158+ , pandoc
159+ , data-default
160+ , bytestring
161+ , yaml
162+ , filepath
163+ , optparse-applicative
164+ , mtl
165+ , aeson
166+ , containers
167+ , doctemplates
168+ , pandoc-types
169+ , prettyprinter-compat-ansi-wl-pprint
170+ ghc-options: -threaded
171+ -rtsopts
172+ -with-rtsopts=-N
173+ other-modules:
174+ FormatHeuristic
175+ Data.OpenApi.Compare.Options
176+
177+executable compaREST-GitHub-Action
178+ import: common-options
179+ hs-source-dirs: github-action
180+ main-is: Main.hs
181+ build-depends:
182+ compaREST
183+ , pandoc
184+ , yaml
185+ , aeson
186+ , github
187+ , freer-simple
188+ , vector
189+ , pandoc-types
190+ , envy
191+ , filepath
192+ , bytestring
193+ ghc-options: -threaded
194+ -rtsopts
195+ -with-rtsopts=-N
196+ other-modules:
197+ Control.Monad.Freer.GitHub
198+ CompaREST.GitHub.API
199+ CompaREST.GitHub.Action.Config
200+ GitHub.Data.Checks
201+ GitHub.Endpoints.Checks
202+
203+test-suite compaREST-tests
204+ import: common-options
205+ type: exitcode-stdio-1.0
206+ hs-source-dirs: test
207+ main-is: Spec.hs
208+ other-modules:
209+ Spec.Golden.Extra
210+ Spec.Golden.TraceTree
211+ Paths_compaREST
212+ autogen-modules: Paths_compaREST
213+ build-depends:
214+ , compaREST
215+ , tasty-golden
216+ , tasty
217+ , bytestring
218+ , yaml
219+ , directory
220+ , filepath
221+ , pandoc
222+ , data-default
223+ , lens
224+ , pandoc-types
225+ ghc-options: -threaded
226+ -rtsopts
227+ -with-rtsopts=-N
css/awsm.min.cssnew file+1
@@ -0,0 +1 @@
1+@charset "UTF-8";html{font-family:"PT Serif",Georgia,serif;font-size:100%;line-height:1.6;background:#fff;color:#000;-webkit-overflow-scrolling:touch}body{margin:1em;font-size:1rem}@media (min-width:20rem){body{font-size:calc(1rem + .0125*(100vw - 20rem))}}@media (min-width:40rem){body{font-size:1.25rem}}body article,body footer,body header,body main{position:relative;max-width:40rem;margin:0 auto}body>header{margin-bottom:3.5em}body>header h1{margin:0;font-size:1.5em}body>header p{margin:0;font-size:.85em}body>footer{margin-top:4.5em;padding-bottom:1.5em;text-align:center;font-size:.8rem;color:#aaa}details,nav,p{margin:1em 0}nav ul{list-style:none;margin:0;padding:0}nav li{display:inline-block;margin-right:1em;margin-bottom:.25em}nav a:visited{color:#0064c1}article header h1 a:visited:hover,article header h2 a:visited:hover,nav a:hover{color:#3000c1}ol,ul{margin-top:0;padding-top:0;padding-left:2.5em}p{-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}aside:first-child,p:first-child{margin-top:0}aside:last-child,p:last-child{margin-bottom:0}p+ol,p+ul{margin-top:-.75em}p img,p picture{float:right;margin-bottom:.5em;margin-left:.5em}p picture img{float:none;margin:0}blockquote,dd{padding-left:2.5em}dd{margin-bottom:1em;margin-left:0}dt{font-weight:700}blockquote{margin:0}aside{margin:.5em 0;font-style:italic;color:#aaa}@media (min-width:65rem){aside{position:absolute;right:-12.5rem;width:9.375rem;max-width:9.375rem;margin:0;padding-left:.5em;font-size:.8em;border-left:1px solid #f2f2f2}}section+section{margin-top:2em}h1,h2,h3,h4,h5,h6{margin:1.25em 0 0;line-height:1.2}h1:focus>a[href^="#"][id],h1:hover>a[href^="#"][id],h2:focus>a[href^="#"][id],h2:hover>a[href^="#"][id],h3:focus>a[href^="#"][id],h3:hover>a[href^="#"][id],h4:focus>a[href^="#"][id],h4:hover>a[href^="#"][id],h5:focus>a[href^="#"][id],h5:hover>a[href^="#"][id],h6:focus>a[href^="#"][id],h6:hover>a[href^="#"][id]{opacity:1;transition:opacity 0s,color 300ms ease-out}figure+p,h1+details,h1+p,h2+details,h2+p,h3+details,h3+p,h4+details,h4+p,h5+details,h5+p,h6+details,h6+p{margin-top:.5em}h1>a[href^="#"][id],h2>a[href^="#"][id],h3>a[href^="#"][id],h4>a[href^="#"][id],h5>a[href^="#"][id],h6>a[href^="#"][id]{position:absolute;left:-.5em;opacity:0;background:0 0;color:rgba(0,0,0,.5);transition:opacity 300ms ease-out}h1>a[href^="#"][id]:focus,h1>a[href^="#"][id]:hover,h1>a[href^="#"][id]:target,h2>a[href^="#"][id]:focus,h2>a[href^="#"][id]:hover,h2>a[href^="#"][id]:target,h3>a[href^="#"][id]:focus,h3>a[href^="#"][id]:hover,h3>a[href^="#"][id]:target,h4>a[href^="#"][id]:focus,h4>a[href^="#"][id]:hover,h4>a[href^="#"][id]:target,h5>a[href^="#"][id]:focus,h5>a[href^="#"][id]:hover,h5>a[href^="#"][id]:target,h6>a[href^="#"][id]:focus,h6>a[href^="#"][id]:hover,h6>a[href^="#"][id]:target{opacity:1;box-shadow:none;color:#000;transition:opacity 0s,color 0s}h1>a[href^="#"][id]:target:focus,h2>a[href^="#"][id]:target:focus,h3>a[href^="#"][id]:target:focus,h4>a[href^="#"][id]:target:focus,h5>a[href^="#"][id]:target:focus,h6>a[href^="#"][id]:target:focus{outline:0}h1>a[href^="#"][id]::before,h2>a[href^="#"][id]::before,h3>a[href^="#"][id]::before,h4>a[href^="#"][id]::before,h5>a[href^="#"][id]::before,h6>a[href^="#"][id]::before{content:"•"}h1{font-size:2em}h2{font-size:1.75em}h3{font-size:1.25em}h4{font-size:1.15em}h5,h6{font-size:1em}h6{margin-top:1em;color:#aaa}article+article{margin-top:5em}article header p{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:.6em;color:#aaa}article header p+h1,article header p+h2{margin-top:-.25em}article header h1+p,article header h2+p{margin-top:.25em}article header h1 a,article header h2 a{color:#000;background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="1"%3E%3Crect x="0" y="0.5" width="1" height="0.5" fill="rgba(0, 0, 0, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){article header h1 a,article header h2 a{background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="2"%3E%3Crect x="0" y="1" width="1" height="1" fill="rgba(0, 0, 0, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}}article header h1 a:visited,article header h2 a:visited{color:#aaa;background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="1"%3E%3Crect x="0" y="0.5" width="1" height="0.5" fill="rgba(170, 170, 170, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){article header h1 a:visited,article header h2 a:visited{background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="2"%3E%3Crect x="0" y="1" width="1" height="1" fill="rgba(170, 170, 170, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}}article>footer{margin-top:1.5em;font-size:.85em}a,abbr{text-decoration:none}a{color:#0064c1;transition:color 300ms ease-out,box-shadow 300ms ease-out;background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="1"%3E%3Crect x="0" y="0.5" width="1" height="0.5" fill="rgba(0, 100, 193, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){a{background:url('data:image/svg+xml;charset=utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="2"%3E%3Crect x="0" y="1" width="1" height="1" fill="rgba(0, 100, 193, 0.35)"/%3E%3C/svg%3E') left bottom repeat-x}}a:visited{color:#80b2e0}a:active,a:hover{outline-width:0}a:hover{box-shadow:inset 0 -1px #3000c1;color:#3000c1;transition:color 0s,box-shadow 0s}abbr{margin-right:-.075em;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none;letter-spacing:.075em;font-size:.9em;border-bottom:1px dotted}img,picture{display:block;max-width:100%;margin:0 auto}audio,video{width:100%;max-width:100%}video{-o-object-position:0 -1px;object-position:0 -1px}figure{margin:1em 0 .5em;padding:0}figure figcaption{opacity:.65;font-size:.85em}table{display:inline-block;border-spacing:0;border-collapse:collapse;overflow-x:auto;max-width:100%;text-align:left;vertical-align:top;background:linear-gradient(rgba(0,0,0,.15) 0%,rgba(0,0,0,.15) 100%) 0 0,linear-gradient(rgba(0,0,0,.15) 0%,rgba(0,0,0,.15) 100%) 100% 0;background-attachment:scroll,scroll;background-size:1px 100%,1px 100%;background-repeat:no-repeat,no-repeat}table caption{font-size:.9em;background:#fff}table td,table th{padding:.35em .75em;vertical-align:top;font-size:.9em;border:1px solid #f2f2f2;border-top:0;border-left:0}table td:first-child,table th:first-child{padding-left:0;background-image:linear-gradient(to right,#fff 50%,rgba(255,255,255,0) 100%);background-size:2px 100%;background-repeat:no-repeat}table td:last-child,table th:last-child{padding-right:0;border-right:0;background-image:linear-gradient(to left,#fff 50%,rgba(255,255,255,0) 100%);background-position:100% 0;background-size:2px 100%;background-repeat:no-repeat}table td:only-child,table th:only-child{background-image:linear-gradient(to right,#fff 50%,rgba(255,255,255,0) 100%),linear-gradient(to left,#fff 50%,rgba(255,255,255,0) 100%);background-position:0 0,100% 0;background-size:2px 100%,2px 100%;background-repeat:no-repeat,no-repeat}table th{line-height:1.2}code,kbd,samp,var{font-family:Consolas,"Lucida Console",Monaco,monospace;font-style:normal}pre{overflow-x:auto;font-size:.8em;background:linear-gradient(rgba(0,0,0,.15) 0%,rgba(0,0,0,.15) 100%) 0 0,linear-gradient(rgba(0,0,0,.15) 0%,rgba(0,0,0,.15) 100%) 100% 0;background-attachment:scroll,scroll;background-size:1px 100%,1px 100%;background-repeat:no-repeat,no-repeat}pre>code,summary{display:inline-block}pre>code{overflow-x:visible;box-sizing:border-box;min-width:100%;border-right:3px solid #fff;border-left:1px solid #fff}hr{height:1px;margin:2em 0;border:0;background:#f2f2f2}details[open]{padding-bottom:.5em;border-bottom:1px solid #f2f2f2}summary{font-weight:700;border-bottom:1px dashed;cursor:pointer}summary::-webkit-details-marker{display:none}noscript{color:#d00000}::selection{background:rgba(0,100,193,.15)}
default.nixnew file+125
@@ -0,0 +1,125 @@
1+{ sources ? import ./nix/sources.nix
2+, haskellNix ? import sources.haskellNix { inherit system; }
3+, pkgs ? import haskellNix.sources.nixpkgs-2311 (haskellNix.nixpkgsArgs // { inherit system; })
4+, system ? builtins.currentSystem
5+, nix-filter ? import sources.nix-filter
6+}:
7+let
8+ masterPkgs = import sources.nixpkgs { inherit system; };
9+ yq = import ./nix/yq.nix { pkgs = masterPkgs; };
10+ diffYaml = import ./nix/diff-yaml.nix { pkgs = masterPkgs; };
11+
12+ hsPkgs = pkgs.haskell-nix.stackProject {
13+ src = nix-filter {
14+ root = ./.;
15+ name = "compaREST";
16+ include = [
17+ ./stack.yaml
18+ ./stack.yaml.lock
19+ ./compaREST.cabal
20+ ];
21+ };
22+
23+ modules = [
24+ {
25+ dontStrip = false;
26+ dontPatchELF = false;
27+ enableDeadCodeElimination = true;
28+ ghcOptions = [
29+ "-O2"
30+ "-fexpose-all-unfoldings"
31+ "-fspecialise-aggressively"
32+ ];
33+ packages.pandoc.ghcOptions = [ "-O1" ];
34+ packages.compaREST.src = nix-filter {
35+ root = ./.;
36+ name = "compaREST-src";
37+ include = with nix-filter; [
38+ (./compaREST.cabal)
39+ (inDirectory ./test)
40+ (inDirectory ./src)
41+ (inDirectory ./app)
42+ (inDirectory ./github-action)
43+ ./css/awsm.min.css
44+ ./LICENSE
45+ ];
46+ };
47+ }
48+ ];
49+ };
50+
51+ staticify = name: drv: pkgs.runCommand name { } ''
52+ mkdir -p $out/bin
53+ cp ${drv + "/bin"}/* $out/bin
54+
55+ ${pkgs.nukeReferences}/bin/nuke-refs $out/bin/*
56+ '';
57+
58+ compaRESTBin = hsPkgs.compaREST.components.exes.compaREST;
59+ compaRESTStaticBin = (staticify "compaREST-static" hsPkgs.projectCross.musl64.hsPkgs.compaREST.components.exes.compaREST);
60+
61+
62+ # doesn't work
63+ armDarwinCompaREST = hsPkgs.projectCross.aarch64-darwin.hsPkgs.compaREST.components.exes.compaREST;
64+
65+ compaRESTImage = pkgs.dockerTools.buildImage {
66+ name = "compaREST";
67+ contents = [ compaRESTStaticBin ];
68+ config = {
69+ Entrypoint = [ "/bin/compaREST" ];
70+ };
71+ };
72+
73+ macOSCompaRESTBundle = pkgs.runCommand "compaREST-macOS-bundled"
74+ {
75+ buildInputs = [ masterPkgs.macdylibbundler ];
76+ } ''
77+ mkdir -p $out/lib
78+ cp ${compaRESTBin}/bin/compaREST $out/compaREST
79+ chmod 755 $out/compaREST
80+ dylibbundler -b \
81+ -x $out/compaREST \
82+ -d $out/lib \
83+ -p '@executable_path/lib'
84+ '';
85+
86+
87+ compaRESTGithubAction =
88+ let
89+ action = staticify "compaREST-GitHub-Action-static" hsPkgs.projectCross.musl64.hsPkgs.compaREST.components.exes.compaREST-GitHub-Action;
90+ wrapped = pkgs.runCommand "wrapped-compaREST-GitHub-Action" { buildInputs = [ pkgs.makeWrapper ]; } ''
91+ makeWrapper ${action}/bin/compaREST-GitHub-Action $out/bin/pre --add-flags "pre"
92+ makeWrapper ${action}/bin/compaREST-GitHub-Action $out/bin/run --add-flags "run"
93+ '';
94+ in
95+ pkgs.dockerTools.buildImage {
96+ name = "typeable/compaREST-GitHub-Action";
97+ tag = "latest";
98+ contents = [ wrapped pkgs.cacert ];
99+ };
100+
101+ WindowsCompaRESTBin = hsPkgs.projectCross.mingwW64.hsPkgs.compaREST.components.exes.compaREST;
102+
103+ # We use the static version so that we don't have to rebuild everything on CI.
104+ # The only binaries build on CI are static.
105+ test = hsPkgs.projectCross.musl64.hsPkgs.compaREST.components.tests.compaREST-tests.overrideAttrs (final: old: {
106+ buildInputs = old.buildInputs ++ [ diffYaml yq ];
107+ nativeBuildInputs = old.nativeBuildInputs ++ (with masterPkgs; [ makeWrapper ]);
108+
109+ postInstall = ''
110+ wrapProgram $out/bin/compaREST-tests \
111+ --prefix PATH : ${masterPkgs.lib.makeBinPath [ diffYaml yq ]}
112+ '';
113+ });
114+in
115+{
116+ inherit
117+ compaRESTImage
118+ compaRESTGithubAction
119+ compaRESTStaticBin
120+ compaRESTBin
121+ hsPkgs
122+ macOSCompaRESTBundle
123+ WindowsCompaRESTBin
124+ test;
125+}
docs/Development_guide.mdnew file+149
@@ -0,0 +1,149 @@
1+CompaREST
2+=========
3+The tool works by simultaneously looking at a pair of nodes in OpenAPI schema
4+trees. At every place we try to understand whether one side (the producer) can
5+produce something that the other side (the consumer) cannot consume. This often
6+involves recursively running the same check on child sub-nodes. The necessary
7+criteria are implemented manually for all types of nodes that appear in the
8+schema. The `Subtree` class in `Data.OpenApi.Compare.Subtree` designates types
9+of nodes for which this compatibility checking is defined. The implementations
10+for various types reside in `Data.OpenApi.Compare.Validate.*`.
11+
12+Producer/Consumer
13+-----------------
14+Rather than looking at which schema is the server's and which is the client's,
15+in terms of compatibility checking it is more useful to track which side is the
16+"producer" and which is the "consumer". At the root of the schema the producer
17+is the client, but as we descend into an HTTP response, the direction flips and
18+the producer becomes the server.
19+
20+We deal with a lot of things in pairs, where one thing belongs to the producer
21+and another belongs to the consumer. The `ProdCons` datatype (in
22+`Data.OpenApi.Compare.Subtree`) is just a pair type that provides an Applicative
23+abstraction for working with two things simultaneously.
24+
25+Trees
26+-----
27+We directly use the datatypes defined in the `openapi3` library. For reasons of
28+identifiability and memoization we tag all nodes in the trees with a path from
29+the root. The tree is heterogeneous (nodes have different types), and every type
30+of node has a different arrangement of children. There is a `Step` data family
31+that defines all the possible children (of a specific type) of a node (of a
32+specific type).
33+
34+A `Trace` is a sequence of steps, except in a path the types of adjacent steps
35+have to agree. The `Paths` datatype achieves this. Together all paths form a
36+`Category`, and we often concatenate them using `>>>`. This is defined in
37+`Data.OpenApi.Compare.Paths`.
38+
39+We often keep a node and a path to it next to each other using an environment
40+comonad. `Traced` is a type alias around `Env` which ensures that the type of
41+the path matches the type of the node.
42+
43+Issues
44+------
45+The output of the tool is a list of compatibility issues that came up during
46+checking. The `Issue` data family describes the kinds of issues that can occur
47+at each type of node. An issue is supposed to characterize a set of interactions
48+(requests or responses) that demonstrate that the schemas are incompatible.
49+
50+Each issue is tagged with a `Behavior` that describes the path to reproducing
51+the issue. While a `Trace` describes a syntactic path down the schema tree, a
52+`Behavior` describes which part of an interaction needs to be focused on for the
53+issue to manifest itself.
54+
55+In most places where we keep multiple issues (e.g. the output), to store them we
56+use a prefix tree map, indexed by both types and values of `Behavior`s. See
57+`Data.OpenApi.Compare.PathsPrefixTree`.
58+
59+Report
60+------
61+The checker ultimately outputs a list of `Issue`s, together with `Behavior`s
62+that cause them. We run the checker twice: forwards and backwards -- to detect
63+non-breaking changes. All of this is then compiled into a report in
64+`Data.OpenApi.Compare.Report`. The tree structure of headings is computed from
65+`Behavior`s, using `Jet`s to collapse particular sequences of behavior steps
66+into a single human-readable header item. The text of each paragraph comes from
67+`describeIssue`.
68+
69+We then use the `pandoc` library to render the report in a variety of formats.
70+
71+Formulas
72+--------
73+The schema has references, so it can end up being recursive. Similarly the
74+process for establishing compatibility can end up being recursive. To keep track
75+of this, the checker actually manipulates *formulas* which can have variables in
76+them, defined in (`Data.OpenApi.Compare.Formula`).
77+
78+A formula represents a set of issues, with the empty set corresponding to a
79+successful compatibility check. A formula can have conjunctions, where we only
80+report success if all parts succeeded, and if not we take the union of all
81+issues. A formula can also have disjunctions, but there it's impossible to
82+guarantee that the issues for the parts also make sense as issues for the whole
83+thing. Due to this if all disjuncted parts have issues we instead return a
84+different issue (usually non-descriptive).
85+
86+The `FormulaF` datatype implements a functor that carries formulaic calculations
87+as well as a result value (a co-Yoneda extension of formulas for the most part).
88+The Applicative interface provides conjunction, and the Alternative interface
89+provides disjunction.
90+
91+When we detect recursion we introduce a variable, compute the compatibility
92+check as a formula with that variable, and then we solve a fixed point equation
93+(`maxFixpoint`) with the variable to obtain the answer.
94+
95+This `FomulaF` is further wrapped in a couple monad transformers
96+(`SemanticCompatFormula`, `StructuralCompatFormula`), and the whole checker is
97+then implemented in the resulting Applicative using ApplicativeDo.
98+
99+Memoization
100+-----------
101+The `Data.OpenApi.Compare.Memo` module contains utilities for stateful
102+memoization and recursion detection. The entire checking process is memoized,
103+and can detect, propagate, and resolve recursion.
104+
105+Structural/Semantic Compatibility
106+---------------------------------
107+When we encounter two nodes we first try to optimistically establish whether
108+they're structurally equal, i.e. the trees are exactly the same modulo reference
109+inlining. This check is also memoized and recursion-aware. If the check succeeds
110+we conclude that the schemas are compatible. Otherwise we fall back to the
111+"normal" semantic compatibility.
112+
113+
114+JSON Schema
115+-----------
116+The language that describes JSON payloads is probably the richest part of
117+OpenAPI schemas, and the checker for it also comes with a lot of moving parts.
118+
119+JSON schema allows arbitrary set arithmetic using `allOf`, `anyOf`, `not` and
120+`oneOf`. To fully check `not` and `oneOf` we would need to compare set
121+subtraction, which involves negating a comparison result. If recursion is
122+involved we would need to be able to solve equations with negation, which we
123+cannot do. So `not` is unsupported altogether, and `oneOf` is only supported
124+when it has disjoint branches and behaves like `anyOf`.
125+
126+With that in mind a JSON schema is first pre-processed into a Disjunctive Normal
127+Form (`DNF` in `Data.OpenApi.Compare.Validate.Schema.DNF`). This pre-processing
128+happens in `Data.OpenApi.Compare.Validate.Schema.Process`.
129+
130+The DNF contains elementary clauses that match on a specific aspect of a JSON
131+object (`Condition`). Most clauses only affect objects of a single type, so JSON
132+values and clauses are segregated by type (`JsonType`, `TypedValue` in
133+`Data.OpenApi.Compare.Validate.Schema.JsonFormula`)
134+
135+Then we reduce the problem of comparing two DNF's to the comparison of a
136+conjunction of clauses in the producer with a single clause in the consumer
137+(`checkFormulas` in `Data.OpenApi.Compare.Validate.Schema`).
138+
139+When we do disjunction in the formula we lose information, so we try to avoid
140+having disjunctions in the consumer DNF. This is done by the means of
141+partitioning. We look for factors that would let us partition the set of all
142+objects into several bins, in a way that hopefully corresponds only a single
143+consumer to each producer. This is implemented in
144+`Data.OpenApi.Compare.Validate.Schema.Partition`. Currently we can only
145+partition by an `enum` value that is accessible via a chain of `required`
146+fields.
147+
148+The same partitioning mechanism is used to test whether the branches of a
149+`oneOf` are disjoint, and emit a warning otherwise.
docs/Integration_guide.mdnew file+49
@@ -0,0 +1,49 @@
1+# Integration guide
2+
3+## Github Actions
4+
5+In cases where your OpenAPI spec can be generated from your code, it can be useful to see how a pull request changes your API. For this very purpose we have a Github Action.
6+
7+### Generating the inputs
8+
9+To use it you need to first get the old (before the pull request) and new (after the pull request) specs.
10+
11+For example:
12+
13+- To get the old spec you can:
14+ - Download from a public "production" server (if your api is public and you provide an OpenAPI spec)
15+ - Checkout the base commit of the pull request and generate is programmatically.
16+
17+ You can checkout the base commit like so in Github Actions:
18+
19+ ```bash
20+ git checkout $(git merge-base ${{ github.event.pull_request.head.sha }} ${{ github.event.pull_request.base.sha }})
21+ ```
22+- To get the new spec you can:
23+ - Build and run the spec generation for the head commit of the pull request
24+
25+### Run the action
26+
27+In our example we have already generated the two OpenAPI specs and placed them in the `old-openapi.yaml` and `new-openapi.yaml` files.
28+
29+We can now run our action:
30+
31+```yaml
32+- uses: typeable/comparest
33+ with:
34+ old: old-openapi.yaml
35+ new: new-openapi.yaml
36+ project_name: TEST
37+```
38+
39+This will create a check on the pull request displaying the changes (if there are any) similar to this:
40+
41+![](img/github-action-report.png)
42+
43+The check will show success when there are no breaking changes, and be neutral otherwise.
44+
45+## Integrating into something other than Github Actions
46+
47+We have a dedicated implementation only for Github Actions. However, we provide a generic CLI which can be used to integrate compaREST into arbitrary workflows and CI systems.
48+
49+You see an example of CLI usage in our [readme](../README.md#assessing-compatibility-automatically).
docs/Releasing.mdnew file+15
@@ -0,0 +1,15 @@
1+# The release procedure
2+
3+1. Update the version number everywhere:
4+ 1. Version in [compaREST.cabal](../compaREST.cabal)
5+ 2. Docker tag in [action.yaml](../action.yaml)
6+ 3. Set the version of unreleased changes in [CHANGELOG.md](../CHANGELOG.md)
7+2. Publish!
8+ 1. Create a pre-release on GitHub:
9+ ![](img/pre-release.png)
10+ 2. This will automatically start the release procedure. You can check the state of it in the "Actions" tab on GitHub:
11+ ![](img/pre-release-ci.png)
12+ 3. If everything goes as planned, the release action should pass and all assets should be added to the release:
13+ ![](img/pre-release-artifacts.png)
14+ 4. The new version should be automatically uploaded a release candidate to [Hackage](https://hackage.haskell.org/package/compaREST/candidates/). Make sure everything looks okay and publish it.
15+ 5. Go to the Releases tab on GitHub and edit the release to make it not a "pre-release".
docs/User_guide.mdnew file+51
@@ -0,0 +1,51 @@
1+CompaREST User Guide
2+====================
3+
4+Running the Tool
5+----------------
6+The tool accepts two OpenAPI 3.0.0 schema files in either JSON or YAML format.
7+One is assumed to be the client version of the schema, and the other is the
8+server version.
9+
10+The tool will look for changes between the schemas and detect whether they are
11+breaking or not -- that is, if they prevent interoperability between the client
12+and the server.
13+
14+Running:
15+```
16+comparest -c client.json -s server.json
17+```
18+will output a markdown report of the changes to the standard output.
19+
20+Compatibility status can be signaled via the exit code using
21+`--signal-exit-code`. In case no report is needed, output can be suppressed with
22+`--silent`. For example:
23+```
24+comparest -c client.json -s server.json --signal-exit-code --silent
25+echo $?
26+```
27+If there were changes that the tool determined to be breaking, the exit code
28+will be 1. If there were some changes the tool couldn't understand, the exit
29+code will be 2. Otherwise if there were no breaking changes, the exit code will
30+be 0.
31+
32+Controlling the Report
33+----------------------
34+By default the report includes breaking changes, as well as non-breaking:
35+changes that would be considered breaking in the opposite direction. To only
36+include breaking changes in the report use `--only-breaking`. The `--all` option
37+restores the default behavior.
38+
39+The report can be formatted in a variety of ways supported by Pandoc. The `-o`
40+option causes the report to be written to a file. The format of the file is
41+determined from the extension. The supported extensions include:
42+ - `.md` for markdown
43+ - `.html` for an HTML snippet
44+ - `.rst` for restructured text
45+ - no extension for a self-contained HTML document with styles
46+
47+By default the report is split up into parts relating to different paths,
48+requests, responses, etc, using headers of various levels. Alternatively, the
49+report can use indended block-quotes to visualize the tree structure of the
50+report. The header style is enabled with `--header-style`, and the block-quote
51+style is enabled with `--folding-block-quotes-style`.
docs/img/github-action-report.pngnew file

Binary file not shown.

docs/img/pre-release-artifacts.pngnew file

Binary file not shown.

docs/img/pre-release-ci.pngnew file

Binary file not shown.

docs/img/pre-release.pngnew file

Binary file not shown.

fourmolu.yamlnew file+8
@@ -0,0 +1,8 @@
1+indentation: 2
2+comma-style: leading # for lists, tuples etc. - can also be 'trailing'
3+record-brace-space: true # rec {x = 1} vs. rec{x = 1}
4+indent-wheres: true # 'false' means save space by only half-indenting the 'where' keyword
5+diff-friendly-import-export: false # 'false' uses Ormolu-style lists
6+respectful: true # don't be too opinionated about newlines etc.
7+haddock-style: single-line # '--' vs. '{-'
8+newlines-between-decls: 1 # number of newlines between top-level declarations
github-action/CompaREST/GitHub/API.hsnew file+86
@@ -0,0 +1,86 @@
1+module CompaREST.GitHub.API
2+ ( postStatus,
3+ postStatusProcessing,
4+ )
5+where
6+
7+import CompaREST.GitHub.Action.Config
8+import Control.Monad.Freer
9+import Control.Monad.Freer.GitHub
10+import Control.Monad.Freer.Reader
11+import Control.Monad.IO.Class
12+import Data.Aeson
13+import qualified Data.ByteString.Lazy.Char8 as BSLC
14+import Data.OpenApi.Compare.Report
15+import Data.Proxy
16+import Data.Text (Text)
17+import GitHub
18+import GitHub.Data.Checks
19+import GitHub.Endpoints.Checks
20+
21+postStatusProcessing ::
22+ (Members '[GitHub, Reader Config] effs, MonadIO (Eff effs)) =>
23+ Eff effs ()
24+postStatusProcessing = do
25+ Config {..} <- ask
26+ printJSON $
27+ sendGitHub $
28+ checkR
29+ repoOwner
30+ repoName
31+ Check
32+ { checkName = mkName Proxy checkName
33+ , checkSha = sha
34+ , checkDetailsURL = Nothing
35+ , checkExternalId = Nothing
36+ , checkStatus = Just CheckInProgress
37+ , checkStartedAt = Nothing
38+ , checkConclusion = Nothing
39+ , checkCompletedAt = Nothing
40+ , checkOutput = Nothing
41+ , checkActions = Nothing
42+ }
43+
44+postStatus ::
45+ (Members '[GitHub, Reader Config] effs, MonadIO (Eff effs)) =>
46+ -- | 'Nothing' means that there were no changes at all
47+ Maybe (Text, ReportStatus) ->
48+ Eff effs ()
49+postStatus x = do
50+ let (body, (title, conclusion)) = case x of
51+ Just (b, s) -> (b,) $ case s of
52+ BreakingChanges -> ("⚠️ Breaking changes found!", CheckNeutral)
53+ NoBreakingChanges -> ("No breaking changes found ✨", CheckSuccess)
54+ OnlyUnsupportedChanges -> ("🤷 Couldn't determine compatibility", CheckNeutral)
55+ Nothing -> ("", ("✅ The API did not change", CheckSuccess))
56+ Config {..} <- ask
57+ printJSON $
58+ sendGitHub $
59+ checkR
60+ repoOwner
61+ repoName
62+ Check
63+ { checkName = mkName Proxy checkName
64+ , checkSha = sha
65+ , checkDetailsURL = Nothing
66+ , checkExternalId = Nothing
67+ , checkStatus = Just CheckCompleted
68+ , checkStartedAt = Nothing
69+ , checkConclusion = Just conclusion
70+ , checkCompletedAt = Nothing
71+ , checkOutput =
72+ Just $
73+ CheckOutput
74+ { checkTitle = title
75+ , checkSummary = body
76+ , checkText = Nothing
77+ , checkAnnotations = Nothing
78+ , checkImages = Nothing
79+ }
80+ , checkActions = Nothing
81+ }
82+
83+printJSON :: MonadIO (Eff effs) => Eff effs Value -> Eff effs ()
84+printJSON m = do
85+ x <- m
86+ liftIO . BSLC.putStrLn $ encode x
github-action/CompaREST/GitHub/Action/Config.hsnew file+47
@@ -0,0 +1,47 @@
1+module CompaREST.GitHub.Action.Config
2+ ( Config (..),
3+ )
4+where
5+
6+import Data.Proxy
7+import Data.Text (Text)
8+import qualified Data.Text as T
9+import qualified GitHub as GH
10+
11+import Data.Functor
12+import System.Envy
13+
14+data Config = Config
15+ { githubToken :: GH.Auth
16+ , repoOwner :: GH.Name GH.Owner
17+ , repoName :: GH.Name GH.Repo
18+ , checkName :: Text
19+ , footerText :: Text
20+ , root :: FilePath
21+ , sha :: GH.Name GH.Commit
22+ }
23+
24+instance FromEnv Config where
25+ fromEnv _ = do
26+ token <- GH.OAuth <$> env "GITHUB_TOKEN"
27+ (owner, repo) <-
28+ T.split (== '/') <$> env "REPO" >>= \case
29+ [owner, name] -> pure (owner, name)
30+ _ -> fail "malformed repo"
31+ checkName <-
32+ envMaybe "PROJECT_NAME" <&> \case
33+ Just pName | not . T.null . T.strip $ pName -> "compaREST – " <> pName
34+ _ -> "compaREST"
35+ footerText <- env "FOOTER"
36+ root <- envMaybe "ROOT" .!= "."
37+ sha <- env "SHA"
38+ pure $
39+ Config
40+ { githubToken = token
41+ , repoOwner = GH.mkName Proxy owner
42+ , repoName = GH.mkName Proxy repo
43+ , checkName = checkName
44+ , footerText = footerText
45+ , root = root
46+ , sha = GH.mkName Proxy sha
47+ }
github-action/Control/Monad/Freer/GitHub.hsnew file+27
@@ -0,0 +1,27 @@
1+module Control.Monad.Freer.GitHub
2+ ( GitHub (..),
3+ runGitHub,
4+ sendGitHub,
5+ )
6+where
7+
8+import Control.Monad.Freer
9+import Control.Monad.Freer.Error
10+import Control.Monad.IO.Class
11+import Data.Aeson
12+import GitHub hiding (Error)
13+import qualified GitHub as GH
14+
15+data GitHub r where
16+ SendGHRequest :: FromJSON x => Request 'RW x -> GitHub x
17+
18+runGitHub :: (Member (Error GH.Error) effs, MonadIO (Eff effs)) => Auth -> Eff (GitHub ': effs) ~> Eff effs
19+runGitHub auth =
20+ interpret
21+ ( \(SendGHRequest req) ->
22+ liftIO (executeRequest auth req)
23+ >>= either throwError pure
24+ )
25+
26+sendGitHub :: (FromJSON x, Member GitHub effs) => Request 'RW x -> Eff effs x
27+sendGitHub req = send $ SendGHRequest req
github-action/GitHub/Data/Checks.hsnew file+173
@@ -0,0 +1,173 @@
1+module GitHub.Data.Checks
2+ ( Check (..),
3+ CheckStatus (..),
4+ CheckConclusion (..),
5+ CheckOutput (..),
6+ CheckAnnotation (..),
7+ CheckAnnotationLevel (..),
8+ CheckImage (..),
9+ CheckAction (..),
10+ )
11+where
12+
13+import Data.Aeson
14+import Data.Aeson.Types
15+import Data.Text (Text)
16+import Data.Vector (Vector)
17+import GHC.Generics (Generic)
18+import GitHub
19+import GitHub.Internal.Prelude (UTCTime)
20+
21+data Check = Check
22+ { checkName :: !(Name Check)
23+ , checkSha :: !(Name Commit)
24+ , checkDetailsURL :: !(Maybe URL)
25+ , checkExternalId :: !(Maybe (Id Check))
26+ , checkStatus :: !(Maybe CheckStatus)
27+ , checkStartedAt :: !(Maybe UTCTime)
28+ , checkConclusion :: !(Maybe CheckConclusion)
29+ , checkCompletedAt :: !(Maybe UTCTime)
30+ , checkOutput :: !(Maybe CheckOutput)
31+ , checkActions :: !(Maybe (Vector CheckAction))
32+ }
33+ deriving stock (Show, Eq, Ord, Generic)
34+
35+instance ToJSON Check where
36+ toJSON (Check n sha durl eid s sa c ca o a) =
37+ object'
38+ [ "name" .= n
39+ , "head_sha" .= sha
40+ , "details_url" .= durl
41+ , "external_id" .= eid
42+ , "status" .= s
43+ , "started_at" .= sa
44+ , "conclusion" .= c
45+ , "completed_at" .= ca
46+ , "output" .= o
47+ , "actions" .= a
48+ ]
49+
50+data CheckStatus
51+ = CheckQueued
52+ | CheckInProgress
53+ | CheckCompleted
54+ deriving stock (Show, Enum, Bounded, Eq, Ord, Generic)
55+
56+instance ToJSON CheckStatus where
57+ toJSON CheckQueued = String "queued"
58+ toJSON CheckInProgress = String "in_progress"
59+ toJSON CheckCompleted = String "completed"
60+
61+data CheckConclusion
62+ = CheckActionRequired
63+ | CheckCancelled
64+ | CheckFailure
65+ | CheckNeutral
66+ | CheckSuccess
67+ | CheckSkipped
68+ | CheckStale
69+ | CheckTimedOut
70+ deriving stock (Show, Enum, Bounded, Eq, Ord, Generic)
71+
72+instance ToJSON CheckConclusion where
73+ toJSON CheckActionRequired = String "action_required"
74+ toJSON CheckCancelled = String "cancelled"
75+ toJSON CheckFailure = String "failure"
76+ toJSON CheckNeutral = String "neutral"
77+ toJSON CheckSuccess = String "success"
78+ toJSON CheckSkipped = String "skipped"
79+ toJSON CheckStale = String "stale"
80+ toJSON CheckTimedOut = String "timed_out"
81+
82+data CheckOutput = CheckOutput
83+ { checkTitle :: !Text
84+ , checkSummary :: !Text
85+ , checkText :: !(Maybe Text)
86+ , checkAnnotations :: !(Maybe (Vector CheckAnnotation))
87+ , checkImages :: !(Maybe (Vector CheckImage))
88+ }
89+ deriving stock (Show, Eq, Ord, Generic)
90+
91+instance ToJSON CheckOutput where
92+ toJSON (CheckOutput t s txt a i) =
93+ object'
94+ [ "title" .= t
95+ , "summary" .= s
96+ , "text" .= txt
97+ , "annotations" .= a
98+ , "images" .= i
99+ ]
100+
101+data CheckAnnotation = CheckAnnotation
102+ { checkPath :: !Text
103+ , checkStartLine :: !Int
104+ , checkEndLine :: !Int
105+ , checkStartColumn :: !(Maybe Int)
106+ , checkEndColumn :: !(Maybe Int)
107+ , checkAnnotationLevel :: !CheckAnnotationLevel
108+ , checkMessage :: !Text
109+ , checkTitle :: !(Maybe Text)
110+ , checkRawDetails :: !(Maybe Text)
111+ }
112+ deriving stock (Show, Eq, Ord, Generic)
113+
114+instance ToJSON CheckAnnotation where
115+ toJSON (CheckAnnotation p sl el sc ec al m t rd) =
116+ object'
117+ [ "path" .= p
118+ , "start_line" .= sl
119+ , "end_line" .= el
120+ , "start_column" .= sc
121+ , "end_column" .= ec
122+ , "annotation_level" .= al
123+ , "message" .= m
124+ , "title" .= t
125+ , "raw_details" .= rd
126+ ]
127+
128+data CheckAnnotationLevel
129+ = NoticeAnnotation
130+ | WarningAnnotation
131+ | FailureAnnotation
132+ deriving stock (Show, Enum, Bounded, Eq, Ord, Generic)
133+
134+instance ToJSON CheckAnnotationLevel where
135+ toJSON NoticeAnnotation = String "notice"
136+ toJSON WarningAnnotation = String "warning"
137+ toJSON FailureAnnotation = String "failure"
138+
139+data CheckImage = CheckImage
140+ { checkImageAlt :: !Text
141+ , checkImageURL :: !URL
142+ , checkImageCaption :: !(Maybe Text)
143+ }
144+ deriving stock (Show, Eq, Ord, Generic)
145+
146+instance ToJSON CheckImage where
147+ toJSON (CheckImage a url c) =
148+ object'
149+ [ "alt" .= a
150+ , "image_url" .= url
151+ , "caption" .= c
152+ ]
153+
154+data CheckAction = CheckAction
155+ { checkActionLabel :: !Text
156+ , checkActionDescription :: !Text
157+ , checkActionIdentifier :: !Text
158+ }
159+ deriving stock (Show, Eq, Ord, Generic)
160+
161+instance ToJSON CheckAction where
162+ toJSON (CheckAction l d i) =
163+ object'
164+ [ "label" .= l
165+ , "description" .= d
166+ , "identifier" .= i
167+ ]
168+
169+object' :: [Pair] -> Value
170+object' = object . filter notNull
171+ where
172+ notNull (_, Null) = False
173+ notNull (_, _) = True
github-action/GitHub/Endpoints/Checks.hsnew file+12
@@ -0,0 +1,12 @@
1+module GitHub.Endpoints.Checks
2+ ( checkR,
3+ )
4+where
5+
6+import Data.Aeson
7+import GitHub
8+import GitHub.Data.Checks
9+
10+checkR :: Name Owner -> Name Repo -> Check -> Request 'RW Value
11+checkR user repo =
12+ command Post ["repos", toPathPart user, toPathPart repo, "check-runs"] . encode
github-action/Main.hsnew file+72
@@ -0,0 +1,72 @@
1+module Main (main) where
2+
3+import CompaREST.GitHub.API
4+import CompaREST.GitHub.Action.Config
5+import Control.Exception
6+import Control.Monad.Freer
7+import Control.Monad.Freer.Error
8+import Control.Monad.Freer.GitHub
9+import Control.Monad.Freer.Reader
10+import Data.OpenApi.Compare.Run
11+import Data.Text (Text)
12+import qualified Data.Text as T
13+import qualified Data.Yaml.Aeson as Yaml
14+import qualified GitHub as GH
15+import System.Environment
16+import System.Envy (decodeEnv)
17+import System.FilePath ((</>))
18+import Text.Pandoc (runPure)
19+import Text.Pandoc.Builder
20+import Text.Pandoc.Options
21+import Text.Pandoc.Writers
22+
23+main :: IO ()
24+main = do
25+ cfg <- decodeEnv >>= either error pure
26+ case sha cfg of
27+ x | T.null . T.strip . GH.untagName $ x -> do
28+ putStrLn "SHA not specified. Exiting without doing anything."
29+ pure ()
30+ _ ->
31+ getArgs >>= \case
32+ ["pre"] -> runPre cfg
33+ ["run"] -> do
34+ oldFile <- getEnv "OLD"
35+ newFile <- getEnv "NEW"
36+ runRun cfg (root cfg </> oldFile) (root cfg </> newFile)
37+ _ -> error "Invalid arguments."
38+
39+runner :: Config -> Eff '[GitHub, Error GH.Error, Reader Config, IO] a -> IO a
40+runner cfg =
41+ runM @IO . runReader cfg
42+ . flip (handleError @GH.Error) (error . displayException)
43+ . runGitHub (githubToken cfg)
44+
45+runPre :: Config -> IO ()
46+runPre cfg = runner cfg postStatusProcessing
47+
48+runRun :: Config -> FilePath -> FilePath -> IO ()
49+runRun cfg old' new' = runner cfg $ do
50+ old <- Yaml.decodeFileThrow old'
51+ new <- Yaml.decodeFileThrow new'
52+ let reportConfig =
53+ ReportConfig
54+ { treeStyle = FoldingBlockquotesTreeStyle
55+ , reportMode = All
56+ }
57+ (report, status) = runReport reportConfig (old, new)
58+
59+ body = markdown report <> "\n\n" <> footerText cfg
60+
61+ result =
62+ if old == new
63+ then Nothing
64+ else Just (body, status)
65+ postStatus result
66+
67+markdown :: Blocks -> Text
68+markdown =
69+ either (error . displayException) id
70+ . runPure
71+ . writeHtml5String def
72+ . doc
nix/ci.nixnew file+11
@@ -0,0 +1,11 @@
1+{ sources ? import ./sources.nix
2+, pkgs ? import sources.nixpkgs { }
3+}:
4+
5+let
6+ yq = import ./yq.nix { inherit pkgs; };
7+ diff-yaml = import ./diff-yaml.nix { inherit pkgs; };
8+in
9+pkgs.mkShell {
10+ packages = [ pkgs.haskellPackages.fourmolu diff-yaml yq ];
11+}
nix/diff-yaml.nixnew file+20
@@ -0,0 +1,20 @@
1+{ pkgs ? import <nixpkgs> {} }:
2+
3+let
4+ inherit (pkgs) stdenv;
5+ yq = import ./yq.nix { inherit pkgs; };
6+in
7+stdenv.mkDerivation {
8+ name = "diff-yaml";
9+
10+ src = ../scripts/diff-yaml;
11+
12+ buildInputs = [ pkgs.bash yq ];
13+
14+ phases = [ "installPhase" ];
15+
16+ installPhase = ''
17+ mkdir -p $out/bin
18+ cp $src $out/bin/diff-yaml
19+ '';
20+}
nix/shell.nixnew file+11
@@ -0,0 +1,11 @@
1+{ sources ? import ./sources.nix
2+, pkgs ? import sources.nixpkgs { }
3+}:
4+
5+let
6+ patched-yq = import ./yq.nix { inherit pkgs; };
7+ diffYaml = import ./diff-yaml.nix { inherit pkgs; };
8+in
9+pkgs.mkShell {
10+ buildInputs = with pkgs; [ pkg-config diffYaml patched-yq zlib ];
11+}
nix/sources.jsonnew file+50
@@ -0,0 +1,50 @@
1+{
2+ "haskellNix": {
3+ "branch": "master",
4+ "description": "Alternative Haskell Infrastructure for Nixpkgs",
5+ "homepage": "https://input-output-hk.github.io/haskell.nix",
6+ "owner": "input-output-hk",
7+ "repo": "haskell.nix",
8+ "rev": "d7f95903c84a5a50d6fe0844280da82c3c81680a",
9+ "sha256": "02870rk4sx44lwwa0k20iwdhqcx0ayz34yb3b0qy045p22q45815",
10+ "type": "tarball",
11+ "url": "https://github.com/input-output-hk/haskell.nix/archive/d7f95903c84a5a50d6fe0844280da82c3c81680a.tar.gz",
12+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
13+ },
14+ "niv": {
15+ "branch": "master",
16+ "description": "Easy dependency management for Nix projects",
17+ "homepage": "https://github.com/nmattia/niv",
18+ "owner": "nmattia",
19+ "repo": "niv",
20+ "rev": "f7c538837892dd2eb83567c9f380a11efb59b53f",
21+ "sha256": "0xl33k24vfc29cg9lnp95kvcq69qbq5fzb7jk9ig4lgrhaarh651",
22+ "type": "tarball",
23+ "url": "https://github.com/nmattia/niv/archive/f7c538837892dd2eb83567c9f380a11efb59b53f.tar.gz",
24+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
25+ },
26+ "nix-filter": {
27+ "branch": "main",
28+ "description": "a small self-container source filtering lib",
29+ "homepage": "",
30+ "owner": "numtide",
31+ "repo": "nix-filter",
32+ "rev": "3342559a24e85fc164b295c3444e8a139924675b",
33+ "sha256": "08xia32g5jzaiyhfl3kzxslzbr4w1i56i0mhy5gpfggv8gqy8sym",
34+ "type": "tarball",
35+ "url": "https://github.com/numtide/nix-filter/archive/3342559a24e85fc164b295c3444e8a139924675b.tar.gz",
36+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
37+ },
38+ "nixpkgs": {
39+ "branch": "master",
40+ "description": "Nix Packages collection",
41+ "homepage": "",
42+ "owner": "NixOS",
43+ "repo": "nixpkgs",
44+ "rev": "bf038bd724982de67a2ee9a6b2f1fcb7d6a87bd7",
45+ "sha256": "0ivvwdmg9fipj6ylq5ipxqpb0xnz6hsx3lyn377jacfpiqi9w0cv",
46+ "type": "tarball",
47+ "url": "https://github.com/NixOS/nixpkgs/archive/bf038bd724982de67a2ee9a6b2f1fcb7d6a87bd7.tar.gz",
48+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
49+ }
50+}
nix/sources.nixnew file+174
@@ -0,0 +1,174 @@
1+# This file has been generated by Niv.
2+
3+let
4+
5+ #
6+ # The fetchers. fetch_<type> fetches specs of type <type>.
7+ #
8+
9+ fetch_file = pkgs: name: spec:
10+ let
11+ name' = sanitizeName name + "-src";
12+ in
13+ if spec.builtin or true then
14+ builtins_fetchurl { inherit (spec) url sha256; name = name'; }
15+ else
16+ pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
17+
18+ fetch_tarball = pkgs: name: spec:
19+ let
20+ name' = sanitizeName name + "-src";
21+ in
22+ if spec.builtin or true then
23+ builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
24+ else
25+ pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
26+
27+ fetch_git = name: spec:
28+ let
29+ ref =
30+ if spec ? ref then spec.ref else
31+ if spec ? branch then "refs/heads/${spec.branch}" else
32+ if spec ? tag then "refs/tags/${spec.tag}" else
33+ abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
34+ in
35+ builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
36+
37+ fetch_local = spec: spec.path;
38+
39+ fetch_builtin-tarball = name: throw
40+ ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
41+ $ niv modify ${name} -a type=tarball -a builtin=true'';
42+
43+ fetch_builtin-url = name: throw
44+ ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
45+ $ niv modify ${name} -a type=file -a builtin=true'';
46+
47+ #
48+ # Various helpers
49+ #
50+
51+ # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
52+ sanitizeName = name:
53+ (
54+ concatMapStrings (s: if builtins.isList s then "-" else s)
55+ (
56+ builtins.split "[^[:alnum:]+._?=-]+"
57+ ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
58+ )
59+ );
60+
61+ # The set of packages used when specs are fetched using non-builtins.
62+ mkPkgs = sources: system:
63+ let
64+ sourcesNixpkgs =
65+ import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
66+ hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
67+ hasThisAsNixpkgsPath = <nixpkgs> == ./.;
68+ in
69+ if builtins.hasAttr "nixpkgs" sources
70+ then sourcesNixpkgs
71+ else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
72+ import <nixpkgs> {}
73+ else
74+ abort
75+ ''
76+ Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
77+ add a package called "nixpkgs" to your sources.json.
78+ '';
79+
80+ # The actual fetching function.
81+ fetch = pkgs: name: spec:
82+
83+ if ! builtins.hasAttr "type" spec then
84+ abort "ERROR: niv spec ${name} does not have a 'type' attribute"
85+ else if spec.type == "file" then fetch_file pkgs name spec
86+ else if spec.type == "tarball" then fetch_tarball pkgs name spec
87+ else if spec.type == "git" then fetch_git name spec
88+ else if spec.type == "local" then fetch_local spec
89+ else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
90+ else if spec.type == "builtin-url" then fetch_builtin-url name
91+ else
92+ abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
93+
94+ # If the environment variable NIV_OVERRIDE_${name} is set, then use
95+ # the path directly as opposed to the fetched source.
96+ replace = name: drv:
97+ let
98+ saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
99+ ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
100+ in
101+ if ersatz == "" then drv else
102+ # this turns the string into an actual Nix path (for both absolute and
103+ # relative paths)
104+ if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
105+
106+ # Ports of functions for older nix versions
107+
108+ # a Nix version of mapAttrs if the built-in doesn't exist
109+ mapAttrs = builtins.mapAttrs or (
110+ f: set: with builtins;
111+ listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
112+ );
113+
114+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
115+ range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
116+
117+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
118+ stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
119+
120+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
121+ stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
122+ concatMapStrings = f: list: concatStrings (map f list);
123+ concatStrings = builtins.concatStringsSep "";
124+
125+ # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
126+ optionalAttrs = cond: as: if cond then as else {};
127+
128+ # fetchTarball version that is compatible between all the versions of Nix
129+ builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
130+ let
131+ inherit (builtins) lessThan nixVersion fetchTarball;
132+ in
133+ if lessThan nixVersion "1.12" then
134+ fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
135+ else
136+ fetchTarball attrs;
137+
138+ # fetchurl version that is compatible between all the versions of Nix
139+ builtins_fetchurl = { url, name ? null, sha256 }@attrs:
140+ let
141+ inherit (builtins) lessThan nixVersion fetchurl;
142+ in
143+ if lessThan nixVersion "1.12" then
144+ fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
145+ else
146+ fetchurl attrs;
147+
148+ # Create the final "sources" from the config
149+ mkSources = config:
150+ mapAttrs (
151+ name: spec:
152+ if builtins.hasAttr "outPath" spec
153+ then abort
154+ "The values in sources.json should not have an 'outPath' attribute"
155+ else
156+ spec // { outPath = replace name (fetch config.pkgs name spec); }
157+ ) config.sources;
158+
159+ # The "config" used by the fetchers
160+ mkConfig =
161+ { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
162+ , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
163+ , system ? builtins.currentSystem
164+ , pkgs ? mkPkgs sources system
165+ }: rec {
166+ # The sources, i.e. the attribute set of spec name to spec
167+ inherit sources;
168+
169+ # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
170+ inherit pkgs;
171+ };
172+
173+in
174+mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
nix/yq.nixnew file+26
@@ -0,0 +1,26 @@
1+{ pkgs ? import <nixpkgs> {} }:
2+
3+# Make yq work inside whatever `stack test` launches.
4+# Nuke this when https://github.com/kislyuk/yq/pull/193 is merged
5+# and nixpkgs includes that fix.
6+
7+let
8+ yq-patch = pkgs.writeText "yq-tty-fix.patch" ''
9+diff --git a/yq/__init__.py b/yq/__init__.py
10+index d95ac4b..ae7d59e 100644
11+--- a/yq/__init__.py
12++++ b/yq/__init__.py
13+@@ -110,7 +110,7 @@ def cli(args=None, input_format="yaml", program_name="yq"):
14+ in_place = args.in_place
15+ delattr(args, "in_place")
16+
17+- if sys.stdin.isatty() and not args.input_streams:
18++ if (sys.stdin is None or sys.stdin.isatty()) and not args.input_streams:
19+ parser.print_help()
20+ sys.exit(2)
21+ elif not args.input_streams:
22+ '';
23+in
24+pkgs.yq.overrideAttrs (final: old: {
25+ patches = old.patches ++ [ yq-patch ];
26+})
openapi-diff.cabaldeleted−179
@@ -1,179 +0,0 @@
1−cabal-version: 2.4
2−name: openapi-diff
3−version: 0.0.0.0
4−synopsis: Compatibility checker for OpenAPI
5−description: Compatibility checker for OpenAPI
6−license: MIT
7−license-file: LICENSE
8−author: Aleksey Uymanov
9−maintainer: Aleksey Uymanov <s9gf4ult@gmail.com>
10−copyright: 2021 Aleksey Uymanov
11−category: Web
12−build-type: Simple
13−extra-doc-files: README.md
14− CHANGELOG.md
15−tested-with: GHC == 8.10.4
16−
17−Flag static
18− Default: False
19− Manual: True
20−
21−common common-options
22− if flag(static)
23− cc-options: -static
24− ld-options: -static -pthread
25− ghc-options: -static
26− ghc-options: -Wall
27− -Wcompat
28− -Widentities
29− -Wincomplete-uni-patterns
30− -Wincomplete-record-updates
31− if impl(ghc >= 8.0)
32− ghc-options: -Wredundant-constraints
33− if impl(ghc >= 8.2)
34− ghc-options: -fhide-source-paths
35− if impl(ghc >= 8.4)
36− ghc-options: -Wmissing-export-lists
37− -Wpartial-fields
38−
39− default-language: Haskell2010
40− build-depends: base >= 4.12.0.0 && < 4.15
41− , aeson
42− , attoparsec
43− , bytestring
44− , containers
45− , comonad
46− , deriving-aeson
47− , generic-data
48− , generic-monoid
49− , http-media
50− , insert-ordered-containers
51− , lattices
52− , lens
53− , mtl
54− , openapi3
55− , optparse-applicative
56− , pcre2
57− , scientific
58− , tagged
59− , text
60− , transformers
61− , typerep-map
62− , unordered-containers
63− , vector
64− , yaml
65− , hashable
66− , pandoc-types
67−
68− default-extensions: ApplicativeDo
69− , BangPatterns
70− , ConstraintKinds
71− , DataKinds
72− , DeriveAnyClass
73− , DeriveFoldable
74− , DeriveFunctor
75− , DeriveGeneric
76− , DeriveTraversable
77− , DerivingStrategies
78− , DerivingVia
79− , DuplicateRecordFields
80− , EmptyDataDeriving
81− , FlexibleContexts
82− , FlexibleInstances
83− , FunctionalDependencies
84− , GADTs
85− , GeneralizedNewtypeDeriving
86− , LambdaCase
87− , MultiParamTypeClasses
88− , MultiWayIf
89− , NamedFieldPuns
90− , NumDecimals
91− , OverloadedStrings
92− , PatternSynonyms
93− , PolyKinds
94− , QuasiQuotes
95− , RankNTypes
96− , RecordWildCards
97− , ScopedTypeVariables
98− , StandaloneDeriving
99− , TemplateHaskell
100− , TupleSections
101− , TypeApplications
102− , TypeFamilies
103− , TypeOperators
104− , UndecidableInstances
105− , ViewPatterns
106− , QuantifiedConstraints
107− , DefaultSignatures
108−
109−library
110− import: common-options
111− hs-source-dirs: src
112− exposed-modules: Data.HList
113− , OpenAPI.Checker.Behavior
114− , OpenAPI.Checker.Formula
115− , OpenAPI.Checker.Memo
116− , OpenAPI.Checker.Options
117− , OpenAPI.Checker.Orphans
118− , OpenAPI.Checker.Paths
119− , OpenAPI.Checker.PathsPrefixTree
120− , OpenAPI.Checker.References
121− , OpenAPI.Checker.Subtree
122− , OpenAPI.Checker.Validate.MediaTypeObject
123− , OpenAPI.Checker.Validate.OpenApi
124− , OpenAPI.Checker.Validate.Operation
125− , OpenAPI.Checker.Validate.Param
126− , OpenAPI.Checker.Validate.PathFragment
127− , OpenAPI.Checker.Validate.Products
128− , OpenAPI.Checker.Validate.RequestBody
129− , OpenAPI.Checker.Validate.Responses
130− , OpenAPI.Checker.Validate.Schema
131− , OpenAPI.Checker.Validate.SecurityRequirement
132− , OpenAPI.Checker.Validate.Server
133− , OpenAPI.Checker.Validate.Sums
134− , OpenAPI.Checker.Validate.Header
135− , OpenAPI.Checker.Validate.Link
136− , OpenAPI.Checker.Common
137− , OpenAPI.Checker.Validate.SecurityScheme
138− , OpenAPI.Checker.Validate.OAuth2Flows
139− , OpenAPI.Checker.Report
140−
141−executable openapi-diff
142− import: common-options
143− hs-source-dirs: app
144− main-is: Main.hs
145− build-depends:
146− openapi-diff
147− , pandoc
148− , data-default
149− , bytestring
150− , yaml
151− , filepath
152− ghc-options: -threaded
153− -rtsopts
154− -with-rtsopts=-N
155− other-modules:
156− FormatHeuristic
157−
158−test-suite openapi-diff-test
159− import: common-options
160− type: exitcode-stdio-1.0
161− hs-source-dirs: test
162− main-is: Spec.hs
163− other-modules:
164− Spec.Golden.Extra
165− Spec.Golden.TraceTree
166− build-depends:
167− , openapi-diff
168− , tasty-golden
169− , tasty
170− , bytestring
171− , aeson
172− , yaml
173− , directory
174− , filepath
175− , pandoc
176− , data-default
177− ghc-options: -threaded
178− -rtsopts
179− -with-rtsopts=-N
scripts/diff-yamlnew file+35
@@ -0,0 +1,35 @@
1+#!/usr/bin/env bash
2+set -e
3+
4+# Normalise YAML files passed as inputs, then run diff on them.
5+
6+check_util() {
7+ local util=$1
8+
9+ if [ -z $util ]; then
10+ echo "Error: $util not found in PATH"
11+ exit 1
12+ fi
13+}
14+
15+DIFF=`which diff`
16+check_util $DIFF
17+
18+YQ=`which yq`
19+check_util $YQ
20+
21+# Only normalise YAML files.
22+# Print anything else as is.
23+normalise() {
24+ local file=$1
25+ local contents=($YQ -y -S '.' $file)
26+
27+ # if $contents contains actual YAML data, print it
28+ if [[ $? == 0 ]]; then
29+ echo $contents
30+ else
31+ cat $file
32+ fi
33+}
34+
35+$DIFF -u <(normalise $1) <(normalise $2)
src/Data/HList.hs+37−7
@@ -1,9 +1,11 @@
11module Data.HList
2− ( Has
3− , HasAll
4− , getH
5− , HList (..)
6− , singletonH
2+ ( Has,
3+ HasAll,
4+ getH,
5+ HList (..),
6+ singletonH,
7+ ReassembleHList,
8+ reassemble,
79 )
810where
911
@@ -31,21 +33,49 @@ class t ~ HeadEq x xs => Has' (x :: Type) (xs :: [Type]) (t :: Bool) where
3133
3234instance Has' x (x ': xs) 'True where
3335 getH (HCons x _) = x
36+ {-# INLINE getH #-}
3437
3538instance (Has' x xs t, HeadEq x (y : xs) ~ 'False) => Has' x (y ': xs) 'False where
3639 getH (HCons _ xs) = getH xs
40+ {-# INLINE getH #-}
3741
3842instance
39− TypeError ('ShowType x ':<>: 'Text " is not a part of the list.")
40− => Has' x '[] 'False
43+ TypeError ( 'ShowType x ':<>: 'Text " is not a part of the list.") =>
44+ Has' x '[] 'False
4145 where
4246 getH HNil = undefined
47+ {-# INLINE getH #-}
4348
4449singletonH :: a -> HList '[a]
4550singletonH a = a `HCons` HNil
51+{-# INLINE singletonH #-}
4652
4753instance Eq (HList '[]) where
4854 HNil == HNil = True
4955
5056instance (Eq x, Eq (HList xs)) => Eq (HList (x ': xs)) where
5157 (HCons x xs) == (HCons y ys) = x == y && xs == ys
58+
59+type family (==) a b :: Bool where
60+ a == a = 'True
61+ _ == _ = 'False
62+
63+type ReassembleHList xs ys = ReassembleHList' xs ys (xs == ys)
64+
65+class f ~ (xs == ys) => ReassembleHList' xs ys f where
66+ reassemble :: HList xs -> HList ys
67+
68+instance ReassembleHList' xs xs 'True where
69+ reassemble = id
70+ {-# INLINE reassemble #-}
71+
72+instance ReassembleHList' (x ': xs) '[] 'False where
73+ reassemble _ = HNil
74+ {-# INLINE reassemble #-}
75+
76+instance
77+ (Has y xs, ReassembleHList' xs ys f, (xs == (y ': ys)) ~ 'False) =>
78+ ReassembleHList' xs (y ': ys) 'False
79+ where
80+ reassemble xs = getH @y xs `HCons` reassemble xs
81+ {-# INLINE reassemble #-}
src/Data/OpenApi/Compare/Behavior.hsnew file+124
@@ -0,0 +1,124 @@
1+module Data.OpenApi.Compare.Behavior
2+ ( BehaviorLevel (..),
3+ Behavable (..),
4+ IssueKind (..),
5+ Issuable (..),
6+ Orientation (..),
7+ toggleOrientation,
8+ Behavior,
9+ AnIssue (..),
10+ withClass,
11+ anIssueKind,
12+ relatedAnIssues,
13+ )
14+where
15+
16+import Data.Aeson
17+import Data.Kind
18+import Data.OpenApi.Compare.Paths
19+import Data.Typeable
20+import Text.Pandoc.Builder
21+
22+-- | Kind
23+data BehaviorLevel
24+ = APILevel
25+ | ServerLevel
26+ | SecurityRequirementLevel
27+ | SecuritySchemeLevel
28+ | PathLevel
29+ | OperationLevel
30+ | PathFragmentLevel
31+ | RequestLevel
32+ | ResponseLevel
33+ | HeaderLevel
34+ | -- | either request or response data
35+ PayloadLevel
36+ | SchemaLevel
37+ | TypedSchemaLevel
38+ | LinkLevel
39+ | CallbackLevel
40+
41+class
42+ (Ord (Behave a b), Show (Behave a b)) =>
43+ Behavable (a :: BehaviorLevel) (b :: BehaviorLevel)
44+ where
45+ data Behave a b
46+ describeBehavior :: Behave a b -> Inlines
47+
48+type instance AdditionalQuiverConstraints Behave a b = Behavable a b
49+
50+data IssueKind
51+ = -- | This is certainly an issue, we can demonstrate a "counterexample"
52+ CertainIssue
53+ | -- | Change looks breaking but we don't have a complete comprehension of the problem
54+ ProbablyIssue
55+ | -- | We don't really support this feature at all, outside structural comparison
56+ Unsupported
57+ | -- | This is not an issue in itself, but a clarifying comment providing context for some other issues
58+ Comment
59+ | -- | We detected an issue with one of the input schemata itself
60+ SchemaInvalid
61+ deriving stock (Eq, Ord, Show)
62+
63+class (Typeable l, Ord (Issue l), Show (Issue l)) => Issuable (l :: BehaviorLevel) where
64+ data Issue l :: Type
65+
66+ -- | The same issues can be rendered in multiple places and might
67+ -- require different ways of represnting them to the user.
68+ --
69+ -- In practice each issue requires a maximum of two different representations:
70+ -- based on the context the issue might need to be rendered as "opposite" ('Backward')
71+ -- – for example when rendering non-breaking changes everything should be
72+ -- reversed (a consequence of the way we generate non-breaking changes).
73+ --
74+ -- If _consumer_ doesn't have something, the element was "removed".
75+ -- If _producer_ doesn't have something, the element was "added".
76+ describeIssue :: Orientation -> Issue l -> Blocks
77+
78+ issueKind :: Issue l -> IssueKind
79+
80+ -- | An equivalence relation designating whether two issues are talking about the aspect of the schema. This is used
81+ -- to remove duplicates from the "reverse" error tree we get when we look for non-breaking changes.
82+ -- Generally if checking X->Y raises issue I, and checking Y->X raises issue J, I and J should be related.
83+ relatedIssues :: Issue l -> Issue l -> Bool
84+ relatedIssues = (==)
85+
86+-- Utility function for 'relatedIssues'. In @withClass eq f@, @f@ attempts to partition inputs into equivalence classes,
87+-- and two items in the same equivalence class are related. If both items aren't assigned to a class by @f@, instead
88+-- @eq@ is used to compare them.
89+withClass :: Eq b => (a -> a -> Bool) -> (a -> Maybe b) -> a -> a -> Bool
90+withClass eq f = \x y -> case (f x, f y) of
91+ (Just fx, Just fy) -> fx == fy
92+ (Nothing, Nothing) -> eq x y
93+ (_, _) -> False
94+
95+data Orientation = Forward | Backward
96+ deriving stock (Eq, Ord, Show)
97+
98+toggleOrientation :: Orientation -> Orientation
99+toggleOrientation Forward = Backward
100+toggleOrientation Backward = Forward
101+
102+-- | A set of interactions having common unifying features
103+type Behavior = Paths Behave 'APILevel
104+
105+instance Issuable l => ToJSON (Issue l) where
106+ toJSON = toJSON . show
107+
108+data AnIssue (l :: BehaviorLevel) where
109+ AnIssue :: Issuable l => Orientation -> Issue l -> AnIssue l
110+
111+deriving stock instance Show (AnIssue l)
112+
113+deriving stock instance Eq (AnIssue l)
114+
115+deriving stock instance Ord (AnIssue l)
116+
117+instance ToJSON (AnIssue l) where
118+ toJSON (AnIssue _ issue) = toJSON issue
119+
120+anIssueKind :: AnIssue l -> IssueKind
121+anIssueKind (AnIssue _ i) = issueKind i
122+
123+relatedAnIssues :: AnIssue l -> AnIssue l -> Bool
124+relatedAnIssues (AnIssue _ x) (AnIssue _ y) = relatedIssues x y
src/OpenAPI/Checker/Common.hs → src/Data/OpenApi/Compare/Common.hsrenamed+2−2
@@ -1,5 +1,5 @@
1−module OpenAPI.Checker.Common
2− ( zipAll
1+module Data.OpenApi.Compare.Common
2+ ( zipAll,
33 )
44where
55
src/OpenAPI/Checker/Formula.hs → src/Data/OpenApi/Compare/Formula.hsrenamed+35−25
@@ -1,20 +1,21 @@
1−module OpenAPI.Checker.Formula
2− ( FormulaF
3− , VarRef
4− , variable
5− , eitherOf
6− , anError
7− , errors
8− , calculate
9− , maxFixpoint
10− , mapErrors
11− ) where
1+module Data.OpenApi.Compare.Formula
2+ ( FormulaF,
3+ VarRef,
4+ variable,
5+ eitherOf,
6+ anError,
7+ errors,
8+ calculate,
9+ maxFixpoint,
10+ mapErrors,
11+ )
12+where
1213
1314import Data.Kind
14−import Data.Monoid
1515import qualified Data.List.NonEmpty as NE
16−import OpenAPI.Checker.Paths
17−import qualified OpenAPI.Checker.PathsPrefixTree as P
16+import Data.Monoid
17+import Data.OpenApi.Compare.Paths
18+import qualified Data.OpenApi.Compare.PathsPrefixTree as P
1819
1920type VarRef = Int
2021
@@ -24,15 +25,24 @@ type VarRef = Int
2425-- fixpoints always exist, i.e. that @x = f x@ has at least one solution.
2526data FormulaF (q :: k -> k -> Type) (f :: k -> Type) (r :: k) (a :: Type) where
2627 Result :: a -> FormulaF q f r a
27− Errors :: !(P.PathsPrefixTree q f r) -> FormulaF q f r a
28− -- ^ invariant: never empty
29− Apply :: FormulaF q f r (b -> c) -> FormulaF q f r b -> (c -> a) -> FormulaF q f r a
30− -- ^ invariant: at least one of LHS and RHS is not 'Errors', and they are
28+ Errors ::
29+ !(P.PathsPrefixTree q f r) ->
30+ -- | invariant: never empty
31+ FormulaF q f r a
32+ Apply ::
33+ FormulaF q f r (b -> c) ->
34+ FormulaF q f r b ->
35+ (c -> a) ->
36+ -- | invariant: at least one of LHS and RHS is not 'Errors', and they are
3137 -- both not 'Result'
32− SelectFirst :: NE.NonEmpty (SomeFormulaF b)
33− -> !(P.PathsPrefixTree q f r) -> (b -> a) -> FormulaF q f r a
34− -- ^ invariant: the list doesn't contain any 'Result's, 'Errors' or
38+ FormulaF q f r a
39+ SelectFirst ::
40+ NE.NonEmpty (SomeFormulaF b) ->
41+ !(P.PathsPrefixTree q f r) ->
42+ (b -> a) ->
43+ -- | invariant: the list doesn't contain any 'Result's, 'Errors' or
3544 -- 'SelectFirst'
45+ FormulaF q f r a
3646 Variable :: !VarRef -> a -> FormulaF q f r a
3747
3848mkApply :: FormulaF q f r (b -> c) -> FormulaF q f r b -> (c -> a) -> FormulaF q f r a
@@ -44,13 +54,13 @@ mkApply f x h = Apply f x h
4454mkSelectFirst :: [SomeFormulaF b] -> P.PathsPrefixTree q f r -> (b -> a) -> FormulaF q f r a
4555mkSelectFirst fs allE h = case foldMap check fs of
4656 (First (Just x), _) -> Result (h x)
47− (First Nothing, x:xs) -> SelectFirst (x NE.:| xs) allE h
57+ (First Nothing, x : xs) -> SelectFirst (x NE.:| xs) allE h
4858 (First Nothing, []) -> Errors allE
4959 where
5060 check (SomeFormulaF (Result x)) = (First (Just x), mempty)
5161 check (SomeFormulaF (Errors _)) = (mempty, mempty)
52− check (SomeFormulaF (SelectFirst xs _ h'))
53− = (mempty, NE.toList (fmap (fmap h') xs))
62+ check (SomeFormulaF (SelectFirst xs _ h')) =
63+ (mempty, NE.toList (fmap (fmap h') xs))
5464 check x = (mempty, [x])
5565
5666data SomeFormulaF (a :: Type) where
@@ -96,7 +106,7 @@ calculate (Apply f x h) = case calculate f of
96106 Right x' -> Right (h (f' x'))
97107calculate (SelectFirst xs e h) = go (NE.toList xs)
98108 where
99− go (SomeFormulaF r:rs) = case calculate r of
109+ go (SomeFormulaF r : rs) = case calculate r of
100110 Left _ -> go rs
101111 Right x -> Right (h x)
102112 go [] = Left e
src/Data/OpenApi/Compare/Memo.hsnew file+164
@@ -0,0 +1,164 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+
3+-- | Utilities for effectfully memoizing other, more effectful functions.
4+module Data.OpenApi.Compare.Memo
5+ ( MonadMemo,
6+ MemoState,
7+ runMemo,
8+ modifyMemoNonce,
9+ KnotTier (..),
10+ unknot,
11+ memoWithKnot,
12+ memoTaggedWithKnot,
13+ )
14+where
15+
16+import Control.Monad.State
17+import Data.Dynamic
18+import qualified Data.Map as M
19+import Data.Tagged
20+import qualified Data.TypeRepMap as T
21+import Data.Void
22+import Type.Reflection
23+
24+data Progress a = Finished a | Started | TyingKnot Dynamic
25+
26+data MemoMap a where
27+ MemoMap :: !(M.Map k (Progress v)) -> MemoMap (k, v)
28+
29+data MemoState s = MemoState s (T.TypeRepMap MemoMap)
30+
31+-- | An effectful memoization monad.
32+type MonadMemo s m = MonadState (MemoState s) m
33+
34+memoStateLookup ::
35+ forall k v s.
36+ (Typeable k, Typeable v, Ord k) =>
37+ k ->
38+ MemoState s ->
39+ Maybe (Progress v)
40+memoStateLookup k (MemoState _ t) = case T.lookup @(k, v) t of
41+ Just (MemoMap m) -> M.lookup k m
42+ Nothing -> Nothing
43+
44+memoStateInsert ::
45+ forall k v s.
46+ (Typeable k, Typeable v, Ord k) =>
47+ k ->
48+ Progress v ->
49+ MemoState s ->
50+ MemoState s
51+memoStateInsert k x (MemoState s t) = MemoState s $ T.insert (MemoMap m'') t
52+ where
53+ m'' = M.insert k x m'
54+ m' = case T.lookup @(k, v) t of
55+ Just (MemoMap m) -> m
56+ Nothing -> M.empty
57+
58+modifyMemoNonce :: MonadMemo s m => (s -> s) -> m s
59+modifyMemoNonce f = do
60+ MemoState s t <- get
61+ put $ MemoState (f s) t
62+ pure s
63+
64+-- | Run a memoized computation.
65+runMemo :: Monad m => s -> StateT (MemoState s) m a -> m a
66+runMemo s = (`evalStateT` MemoState s T.empty)
67+
68+-- | 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.
70+data KnotTier v d m = KnotTier
71+ { -- | 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
74+ -- to the inner computations
75+ onKnotUsed :: d -> m v
76+ , -- | Once we're done and we're outside, tie the
77+ -- knot using the datum
78+ tieKnot :: d -> v -> m v
79+ }
80+
81+unknot :: KnotTier v Void m
82+unknot =
83+ KnotTier
84+ { onKnotFound = error "Recursion detected"
85+ , onKnotUsed = absurd
86+ , tieKnot = absurd
87+ }
88+
89+-- | 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
91+-- attempt to run the computation with the same key is made, we run a
92+-- tying-the-knot procedure.
93+--
94+-- If another attempt to run the computation with the same key is made
95+-- *after we're done*, we will return the memoized value.
96+memoWithKnot ::
97+ forall k v d m s.
98+ (Typeable k, Typeable v, Typeable d, Ord k, MonadMemo s m) =>
99+ KnotTier v d m ->
100+ -- | the computation to memoize
101+ m v ->
102+ -- | key for memoization
103+ k ->
104+ m v
105+memoWithKnot tier f k =
106+ memoStateLookup @k @v k <$> get >>= \case
107+ Just (Finished v) -> pure v
108+ Just Started -> do
109+ d <- onKnotFound tier
110+ modify $ memoStateInsert @k @v k (TyingKnot $ toDyn d)
111+ onKnotUsed tier d
112+ Just (TyingKnot dyn) -> case fromDynamic dyn of
113+ Just d -> onKnotUsed tier d
114+ Nothing ->
115+ error $
116+ "Type mismatch when examining the knot of "
117+ <> show (typeRep @(k -> v))
118+ <> ": expected "
119+ <> show (typeRep @d)
120+ <> ", got "
121+ <> show (dynTypeRep dyn)
122+ Nothing -> do
123+ modify $ memoStateInsert @k @v k Started
124+ v <- f
125+ v' <-
126+ memoStateLookup @k @v k <$> get >>= \case
127+ Just Started -> pure v
128+ Just (TyingKnot dyn) -> case fromDynamic dyn of
129+ Just d -> tieKnot tier d v
130+ Nothing ->
131+ error $
132+ "Type mismatch when tying the knot of "
133+ <> show (typeRep @(k -> v))
134+ <> ": expected "
135+ <> show (typeRep @d)
136+ <> ", got "
137+ <> show (dynTypeRep dyn)
138+ Just (Finished _) ->
139+ error $
140+ "Unexpected Finished when memoizing "
141+ <> show (typeRep @(k -> v))
142+ Nothing -> pure v
143+ -- Normally this would be an error, but the underlying monad can refuse
144+ -- to remember memoization state
145+ modify $ memoStateInsert @k @v k (Finished v')
146+ pure v'
147+
148+-- | Disambiguate memoized computations with an arbitrary tag.
149+memoTaggedWithKnot ::
150+ forall t k v d m s.
151+ ( Typeable t
152+ , Typeable k
153+ , Typeable v
154+ , Typeable d
155+ , Ord k
156+ , MonadMemo s m
157+ ) =>
158+ KnotTier v d m ->
159+ m v ->
160+ k ->
161+ m v
162+memoTaggedWithKnot tier f k =
163+ withTypeable (typeRepKind $ typeRep @t) $
164+ memoWithKnot tier f (Tagged @t k)
src/OpenAPI/Checker/Orphans.hs → src/Data/OpenApi/Compare/Orphans.hsrenamed+1−1
@@ -1,6 +1,6 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.Orphans () where
3+module Data.OpenApi.Compare.Orphans () where
44
55import Control.Comonad.Env
66import qualified Data.HashMap.Strict.InsOrd as IOHM
src/OpenAPI/Checker/Paths.hs → src/Data/OpenApi/Compare/Paths.hsrenamed+13−16
@@ -1,25 +1,22 @@
11-- | Utilities for traversing heterogeneous trees. A heterogeneous tree is a
22-- collection of datatypes that "contain" eachother in some form of tree
33-- structure.
4−module OpenAPI.Checker.Paths
5− ( NiceQuiver
6− , AdditionalQuiverConstraints
7− , Paths (..)
8− , DiffPaths (..)
9− , catDiffPaths
10− , _DiffPaths
11− , AnItem (..)
12− , step
4+module Data.OpenApi.Compare.Paths
5+ ( NiceQuiver,
6+ AdditionalQuiverConstraints,
7+ Paths (..),
8+ DiffPaths (..),
9+ catDiffPaths,
10+ AnItem (..),
11+ step,
1312
1413 -- * Reexports
15− , (>>>)
16− , (<<<)
14+ (>>>),
15+ (<<<),
1716 )
1817where
1918
2019import Control.Category
21−import Control.Comonad.Env
22−import Control.Lens
2320import Data.Kind
2421import Data.Type.Equality
2522import Type.Reflection
@@ -87,9 +84,9 @@ newtype DiffPaths (q :: k -> k -> Type) (a :: k) (b :: k)
8784catDiffPaths :: DiffPaths q a b -> DiffPaths q b c -> DiffPaths q a c
8885catDiffPaths (DiffPaths f) (DiffPaths g) = DiffPaths (g . f)
8986
90−_DiffPaths :: Iso (DiffPaths q a b) (DiffPaths q c d) (Paths q a b) (Paths q c d)
91−_DiffPaths = dimap (\(DiffPaths f) -> f Root) $
92− fmap $ \xs -> DiffPaths (>>> xs)
87+-- _DiffPaths :: Iso (DiffPaths q a b) (DiffPaths q c d) (Paths q a b) (Paths q c d)
88+-- _DiffPaths = dimap (\(DiffPaths f) -> f Root) $
89+-- fmap $ \xs -> DiffPaths (>>> xs)
9390
9491-- | An item related to some path relative to the root @r@.
9592data AnItem (q :: k -> k -> Type) (f :: k -> Type) (r :: k) where
src/OpenAPI/Checker/PathsPrefixTree.hs → src/Data/OpenApi/Compare/PathsPrefixTree.hsrenamed+120−55
@@ -1,48 +1,96 @@
11{-# LANGUAGE QuantifiedConstraints #-}
22
3−module OpenAPI.Checker.PathsPrefixTree
4− ( PathsPrefixTree (PathsPrefixNode)
5− , AStep (..)
6− , empty
7− , singleton
8− , fromList
9− , null
10− , foldWith
11− , toList
12− , filter
13− , embed
3+module Data.OpenApi.Compare.PathsPrefixTree
4+ ( PathsPrefixTree (PathsPrefixNode),
5+ AStep (..),
6+ empty,
7+ singleton,
8+ fromList,
9+ null,
10+ foldWith,
11+ toList,
12+ filter,
13+ filterWithKey,
14+ takeSubtree,
15+ lookup,
16+ embed,
17+ size,
18+ partition,
19+ map,
1420 )
1521where
1622
23+import Control.Monad
1724import Data.Aeson
1825import Data.Foldable hiding (null, toList)
19−import qualified Data.HashMap.Strict as HM
26+import qualified Data.Aeson.Key as Key
27+import qualified Data.Aeson.KeyMap as KeyMap
2028import Data.Kind
2129import qualified Data.Map as M
2230import Data.Monoid
31+import Data.OpenApi.Compare.Paths
2332import qualified Data.Set as S
2433import qualified Data.Text as T
2534import Data.Type.Equality
2635import qualified Data.TypeRepMap as TRM
2736import qualified Data.Vector as V
2837import qualified GHC.Exts as Exts
29−import qualified GHC.Exts as TRM
30−import OpenAPI.Checker.Paths
3138import Type.Reflection
32−import Prelude hiding (filter, null)
39+import Prelude hiding (filter, lookup, map, null)
3340
3441-- | A list of @AnItem r f@, but optimized into a prefix tree.
3542data PathsPrefixTree (q :: k -> k -> Type) (f :: k -> Type) (r :: k) = PathsPrefixTree
3643 { rootItems :: !(ASet (f r))
3744 , snocItems :: !(TRM.TypeRepMap (AStep q f r))
3845 }
46+ deriving stock (Show)
47+
48+map :: (forall x. f x -> f x) -> PathsPrefixTree q f r -> PathsPrefixTree q f r
49+map f (PathsPrefixTree roots branches) =
50+ PathsPrefixTree (mapASet f roots) (TRM.hoist (mapAStep f) branches)
51+
52+-- TODO: optimize
53+partition :: (forall a. f a -> Bool) -> PathsPrefixTree q f r -> (PathsPrefixTree q f r, PathsPrefixTree q f r)
54+partition f x = (filter f x, filter (not . f) x)
55+
56+filter :: (forall a. f a -> Bool) -> PathsPrefixTree q f r -> PathsPrefixTree q f r
57+filter f (PathsPrefixTree roots branches) = PathsPrefixTree roots' branches'
58+ where
59+ roots' = filterASet f roots
60+ branches' =
61+ Exts.fromList
62+ . fmap (\(TRM.WrapTypeable (AStep x)) -> TRM.WrapTypeable . AStep . M.mapMaybe (maybeNonEmpty . filter f) $ x)
63+ . Exts.toList
64+ $ branches
65+
66+ maybeNonEmpty = mfilter (not . null) . Just
67+
68+filterWithKey :: (forall a. Paths q r a -> f a -> Bool) -> PathsPrefixTree q f r -> PathsPrefixTree q f r
69+filterWithKey = go Root
70+ where
71+ go :: Paths q r b -> (forall a. Paths q r a -> f a -> Bool) -> PathsPrefixTree q f b -> PathsPrefixTree q f b
72+ go xs f (PathsPrefixTree roots branches) = PathsPrefixTree roots' branches'
73+ where
74+ roots' = filterASet (f xs) roots
75+ branches' =
76+ Exts.fromList
77+ . fmap (\(TRM.WrapTypeable (AStep x)) -> TRM.WrapTypeable . AStep . M.mapMaybeWithKey (\k -> maybeNonEmpty . go (xs `Snoc` k) f) $ x)
78+ . Exts.toList
79+ $ branches
80+
81+ maybeNonEmpty = mfilter (not . null) . Just
82+
83+-- | The number of leaves.
84+size :: PathsPrefixTree q f r -> Int
85+size (PathsPrefixTree root branches) =
86+ (S.size . toSet $ root)
87+ + (sum . fmap (\(TRM.WrapTypeable (AStep x)) -> sum . fmap size . M.elems $ x) . Exts.toList $ branches)
3988
4089pattern PathsPrefixNode :: Ord (f r) => S.Set (f r) -> [TRM.WrapTypeable (AStep q f r)] -> PathsPrefixTree q f r
4190pattern PathsPrefixNode s steps <-
4291 (\(PathsPrefixTree aset m) -> (toSet aset, Exts.toList m) -> (s, steps))
4392 where
44− PathsPrefixNode s steps | S.null s = PathsPrefixTree AnEmptySet (Exts.fromList steps)
45− PathsPrefixNode s steps = PathsPrefixTree (ASet s) (Exts.fromList steps)
93+ PathsPrefixNode s steps = PathsPrefixTree (fromSet s) (Exts.fromList steps)
4694
4795{-# COMPLETE PathsPrefixNode #-}
4896
@@ -51,15 +99,15 @@ instance (forall a. ToJSON (f a)) => ToJSON (PathsPrefixTree q f r) where
5199 Object . getMergableObject
52100 . foldWith (\t x -> MergableObject . traceObject t $ toJSON x)
53101
54−deriving instance Eq (PathsPrefixTree q f a)
102+deriving stock instance Eq (PathsPrefixTree q f a)
55103
56104-- Kind of orphan. Treat the map as an infinite tuple of @Maybe (f a)@'s, where
57105-- the components are ordered by the @SomeTypeRep@ of the @a@.
58−compareTRM
59− :: (forall a. Typeable a => Ord (f a))
60− => TRM.TypeRepMap f
61− -> TRM.TypeRepMap f
62− -> Ordering
106+compareTRM ::
107+ (forall a. Typeable a => Ord (f a)) =>
108+ TRM.TypeRepMap f ->
109+ TRM.TypeRepMap f ->
110+ Ordering
63111compareTRM s1 s2 =
64112 foldMap (\k -> compareMaybe compareW (M.lookup k m1) (M.lookup k m2)) mKeys
65113 where
@@ -69,44 +117,55 @@ compareTRM s1 s2 =
69117 compareMaybe _ Nothing (Just _) = LT
70118 compareMaybe _ (Just _) Nothing = GT
71119 compareMaybe cmp (Just x) (Just y) = cmp x y
72− compareW
73− :: (forall a. Typeable a => Ord (f a))
74− => TRM.WrapTypeable f
75− -> TRM.WrapTypeable f
76− -> Ordering
120+ compareW ::
121+ (forall a. Typeable a => Ord (f a)) =>
122+ TRM.WrapTypeable f ->
123+ TRM.WrapTypeable f ->
124+ Ordering
77125 compareW (TRM.WrapTypeable (x :: f a)) (TRM.WrapTypeable (y :: f b))
78126 | Just Refl <- testEquality (typeRep @a) (typeRep @b) = compare x y
79127 | otherwise = EQ -- unreachable
80128 toMap s =
81129 M.fromList
82− [(someTypeRep x, w) | w@(TRM.WrapTypeable x) <- TRM.toList s]
130+ [(someTypeRep x, w) | w@(TRM.WrapTypeable x) <- Exts.toList s]
83131
84132instance Ord (PathsPrefixTree q f a) where
85133 compare (PathsPrefixTree r1 s1) (PathsPrefixTree r2 s2) =
86134 compare r1 r2 <> compareTRM s1 s2
87135
136+filterASet :: (a -> Bool) -> ASet a -> ASet a
137+filterASet _ AnEmptySet = AnEmptySet
138+filterASet f (ASet s) = fromSet $ S.filter f s
139+
88140data ASet (a :: Type) where
89141 AnEmptySet :: ASet a
90142 ASet :: Ord a => S.Set a -> ASet a
91143
144+mapASet :: (Ord a => Ord b) => (a -> b) -> ASet a -> ASet b
145+mapASet _ AnEmptySet = AnEmptySet
146+mapASet f (ASet s) = ASet $ S.map f s
147+
148+deriving stock instance Show a => Show (ASet a)
149+
92150toSet :: ASet a -> S.Set a
93151toSet AnEmptySet = S.empty
94152toSet (ASet s) = s
95153
154+fromSet :: Ord a => S.Set a -> ASet a
155+fromSet s | S.null s = AnEmptySet
156+fromSet s = ASet s
157+
96158instance ToJSON a => ToJSON (ASet a) where
97− toJSON =
98− toJSON . \case
99− AnEmptySet -> S.empty
100− ASet s -> s
159+ toJSON = toJSON . toSet
101160
102161instance Semigroup (ASet a) where
103162 AnEmptySet <> s = s
104163 s <> AnEmptySet = s
105164 ASet s1 <> ASet s2 = ASet $ S.union s1 s2
106165
107−deriving instance Eq (ASet a)
166+deriving stock instance Eq (ASet a)
108167
109−deriving instance Ord (ASet a)
168+deriving stock instance Ord (ASet a)
110169
111170-- type traceprefixset = traceprefixtree proxy
112171
@@ -114,14 +173,17 @@ instance Monoid (ASet a) where
114173 mempty = AnEmptySet
115174
116175data AStep (q :: k -> k -> Type) (f :: k -> Type) (r :: k) (a :: k) where
117− AStep
118− :: NiceQuiver q r a =>
119− !(M.Map (q r a) (PathsPrefixTree q f a))
120− -> AStep q f r a
176+ AStep ::
177+ NiceQuiver q r a =>
178+ !(M.Map (q r a) (PathsPrefixTree q f a)) ->
179+ AStep q f r a
180+
181+mapAStep :: (forall x. f x -> f x) -> AStep q f r a -> AStep q f r a
182+mapAStep f (AStep m) = AStep $ M.map (map f) m
121183
122−deriving instance Eq (AStep q f r a)
184+deriving stock instance Eq (AStep q f r a)
123185
124−deriving instance Ord (AStep q f r a)
186+deriving stock instance Ord (AStep q f r a)
125187
126188singleton :: AnItem q f r -> PathsPrefixTree q f r
127189singleton (AnItem ys v) = go ys $ PathsPrefixTree (ASet $ S.singleton v) TRM.empty
@@ -154,12 +216,12 @@ null :: PathsPrefixTree q f r -> Bool
154216null (PathsPrefixTree AnEmptySet s) = all (\(TRM.WrapTypeable (AStep x)) -> all null x) (Exts.toList s)
155217null _ = False
156218
157−foldWith
158− :: forall q f m r.
159− Monoid m
160− => (forall a. Ord (f a) => Paths q r a -> f a -> m)
161− -> PathsPrefixTree q f r
162− -> m
219+foldWith ::
220+ forall q f m r.
221+ Monoid m =>
222+ (forall a. Ord (f a) => Paths q r a -> f a -> m) ->
223+ PathsPrefixTree q f r ->
224+ m
163225foldWith k = goTPT Root
164226 where
165227 goTPT :: forall a. Paths q r a -> PathsPrefixTree q f a -> m
@@ -168,7 +230,7 @@ foldWith k = goTPT Root
168230 goASet _ AnEmptySet = mempty
169231 goASet xs (ASet rs) = foldMap (k xs) rs
170232 goTRM :: forall a. Paths q r a -> TRM.TypeRepMap (AStep q f a) -> m
171− goTRM xs s = foldMap (\(TRM.WrapTypeable f) -> goAStep xs f) $ TRM.toList s
233+ goTRM xs s = foldMap (\(TRM.WrapTypeable f) -> goAStep xs f) $ Exts.toList s
172234 goAStep :: forall a b. Paths q r a -> AStep q f a b -> m
173235 goAStep xs (AStep m) =
174236 M.foldrWithKey (\x t -> (goTPT (Snoc xs x) t <>)) mempty m
@@ -177,11 +239,14 @@ toList :: PathsPrefixTree q f r -> [AnItem q f r]
177239toList t = appEndo (foldWith (\xs f -> Endo (AnItem xs f :)) t) []
178240
179241-- | Select a subtree by prefix
180−filter :: forall q f r a. Paths q r a -> PathsPrefixTree q f r -> PathsPrefixTree q f a
181−filter Root t = t
182−filter (Snoc xs x) t =
242+takeSubtree :: forall q f r a. Paths q r a -> PathsPrefixTree q f r -> PathsPrefixTree q f a
243+takeSubtree Root t = t
244+takeSubtree (Snoc xs x) t =
183245 foldMap (\(AStep m) -> fold $ M.lookup x m) $
184− TRM.lookup @a $ snocItems $ filter xs t
246+ TRM.lookup @a $ snocItems $ takeSubtree xs t
247+
248+lookup :: Paths q r a -> PathsPrefixTree q f r -> S.Set (f a)
249+lookup xs = toSet . rootItems . takeSubtree xs
185250
186251-- | Embed a subtree in a larger tree with given prefix
187252embed :: Paths q r a -> PathsPrefixTree q f a -> PathsPrefixTree q f r
@@ -192,7 +257,7 @@ newtype MergableObject = MergableObject {getMergableObject :: Object}
192257
193258instance Semigroup MergableObject where
194259 (MergableObject x) <> (MergableObject y) =
195− MergableObject $ HM.unionWith mergeValue x y
260+ MergableObject $ KeyMap.unionWith mergeValue x y
196261 where
197262 mergeValue :: Value -> Value -> Value
198263 mergeValue (Object a) (Object b) =
@@ -207,6 +272,6 @@ instance Monoid MergableObject where
207272
208273traceObject :: Paths q r a -> Value -> Object
209274traceObject Root (Object o) = o
210−traceObject Root v = HM.singleton "root" v
275+traceObject Root v = KeyMap.singleton "root" v
211276traceObject (root `Snoc` s) v =
212− traceObject root . Object $ HM.singleton (T.pack . show $ s) v
277+ traceObject root . Object $ KeyMap.singleton (Key.fromText . T.pack . show $ s) v
src/OpenAPI/Checker/References.hs → src/Data/OpenApi/Compare/References.hsrenamed+18−19
@@ -1,9 +1,9 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.References
4− ( Step (..)
5− , dereference
6− , Typeable
3+module Data.OpenApi.Compare.References
4+ ( Step (..),
5+ dereference,
6+ Typeable,
77 )
88where
99
@@ -11,19 +11,18 @@ import Data.HList
1111import qualified Data.HashMap.Strict.InsOrd as IOHM
1212import Data.Maybe
1313import Data.OpenApi
14−import Data.Typeable
15−import OpenAPI.Checker.Orphans ()
16−import OpenAPI.Checker.Subtree
14+import Data.OpenApi.Compare.Orphans ()
15+import Data.OpenApi.Compare.Subtree
1716
1817instance Typeable a => Steppable (Referenced a) a where
1918 data Step (Referenced a) a = InlineStep
2019 deriving stock (Eq, Ord, Show)
2120
22−dereference
23− :: Typeable a
24− => Traced (Definitions a)
25− -> Traced (Referenced a)
26− -> Traced a
21+dereference ::
22+ Typeable a =>
23+ Traced (Definitions a) ->
24+ Traced (Referenced a) ->
25+ Traced a
2726dereference defs x = case extract x of
2827 Inline a ->
2928 traced (ask x >>> step InlineStep) a
@@ -34,16 +33,16 @@ instance Subtree a => Subtree (Referenced a) where
3433 type CheckEnv (Referenced a) = ProdCons (Traced (Definitions a)) ': CheckEnv a
3534 type SubtreeLevel (Referenced a) = SubtreeLevel a
3635
37− checkStructuralCompatibility env pc' = do
36+ checkStructuralCompatibility (defs `HCons` env) pc' = do
3837 let pc = do
3938 x <- pc'
40− defs <- getH @(ProdCons (Traced (Definitions a))) env
41− pure (dereference defs x)
39+ defs' <- defs
40+ pure (dereference defs' x)
4241 checkSubstructure env pc
4342
44− checkSemanticCompatibility env bhv pc' = do
43+ checkSemanticCompatibility (defs `HCons` env) bhv pc' = do
4544 let pc = do
4645 x <- pc'
47− defs <- getH @(ProdCons (Traced (Definitions a))) env
48− pure (dereference defs x)
49− checkCompatibility env bhv pc
46+ defs' <- defs
47+ pure (dereference defs' x)
48+ checkCompatibility bhv env pc
src/Data/OpenApi/Compare/Report.hsnew file+399
@@ -0,0 +1,399 @@
1+module Data.OpenApi.Compare.Report
2+ ( generateReport,
3+ CheckerOutput (..),
4+ ReportInput (..),
5+ segregateIssues,
6+ ReportStatus (..),
7+ Pandoc,
8+ ReportConfig (..),
9+ ReportTreeStyle (..),
10+ ReportMode (..),
11+ )
12+where
13+
14+import Control.Monad.Free hiding (unfoldM)
15+import Data.Aeson (ToJSON)
16+import Data.Default
17+import Data.Either
18+import Data.Function
19+import Data.Functor
20+import Data.List.NonEmpty
21+import qualified Data.List.NonEmpty as NE
22+import qualified Data.Map as M
23+import Data.Map.Ordered (OMap)
24+import qualified Data.Map.Ordered as OM
25+import Data.Maybe
26+import Data.OpenApi.Compare.Behavior
27+import Data.OpenApi.Compare.Paths
28+import Data.OpenApi.Compare.PathsPrefixTree hiding (empty)
29+import qualified Data.OpenApi.Compare.PathsPrefixTree as P hiding (empty)
30+import Data.OpenApi.Compare.Report.Jet
31+import Data.OpenApi.Compare.Subtree (invertIssueOrientationP)
32+import Data.OpenApi.Compare.Validate.OpenApi
33+import Data.OpenApi.Compare.Validate.Schema.Issues
34+import Data.OpenApi.Compare.Validate.Schema.TypedJson
35+import Data.OpenUnion
36+import Data.OpenUnion.Extra
37+import Data.Set
38+import qualified Data.Set as S
39+import Data.Text (Text)
40+import qualified Data.Text as T
41+import Data.TypeRepMap hiding (empty)
42+import Data.Typeable
43+import Generic.Data
44+import Text.Pandoc.Builder
45+
46+type Changes = P.PathsPrefixTree Behave AnIssue 'APILevel
47+
48+data CheckerOutput = CheckerOutput
49+ { forwardChanges :: Changes
50+ , backwardChanges :: Changes
51+ }
52+ deriving stock (Generic)
53+ deriving (Semigroup, Monoid) via (Generically CheckerOutput)
54+ deriving anyclass (ToJSON)
55+
56+data ReportInput = ReportInput
57+ { -- | forward 'CertainIssue', 'ProbablyIssue' and 'Comment'
58+ breakingChanges :: Changes
59+ , -- | backward 'CertainIssue', 'ProbablyIssue' and 'Comment', except those shadowed by 'relatedIssues'
60+ nonBreakingChanges :: Changes
61+ , -- | 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
65+ }
66+ deriving stock (Generic)
67+ deriving (Semigroup, Monoid) via (Generically ReportInput)
68+ deriving anyclass (ToJSON)
69+
70+segregateIssues :: CheckerOutput -> ReportInput
71+segregateIssues CheckerOutput {forwardChanges = fwd, backwardChanges = bck} =
72+ ReportInput
73+ { breakingChanges = P.filter isBreaking fwd
74+ , nonBreakingChanges = invertIssueOrientationP $ P.filterWithKey isNonBreaking bck
75+ , unsupportedChanges = P.filter isUnsupported fwd <> P.filter isUnsupported bck
76+ , schemaIssues = P.filter isSchemaIssue fwd <> P.filter isSchemaIssue bck
77+ }
78+ where
79+ isBreaking i = anIssueKind i `elem` [CertainIssue, ProbablyIssue, Comment]
80+ isNonBreaking :: Paths Behave 'APILevel a -> AnIssue a -> Bool
81+ isNonBreaking xs i = isBreaking i && all (\j -> not $ relatedAnIssues i j) (P.lookup xs fwd)
82+ isUnsupported i = anIssueKind i == Unsupported
83+ isSchemaIssue i = anIssueKind i == SchemaInvalid
84+
85+data ReportStatus
86+ = BreakingChanges
87+ | NoBreakingChanges
88+ | -- | All changes that could be breaking are unsupported – we don't know if
89+ -- there actually are any breaking changes.
90+ OnlyUnsupportedChanges
91+
92+data ReportMode = OnlyErrors | All
93+ deriving stock (Eq)
94+
95+data ReportConfig = ReportConfig
96+ { treeStyle :: ReportTreeStyle
97+ , reportMode :: ReportMode
98+ }
99+
100+instance Default ReportConfig where
101+ def =
102+ ReportConfig
103+ { treeStyle = HeadersTreeStyle
104+ , reportMode = All
105+ }
106+
107+data ReportTreeStyle = HeadersTreeStyle | FoldingBlockquotesTreeStyle
108+
109+twoRowTable :: [(Inlines, Inlines)] -> Blocks
110+twoRowTable x = simpleTable (para . fst <$> x) [para . snd <$> x]
111+
112+generateReport :: ReportConfig -> ReportInput -> (Blocks, ReportStatus)
113+generateReport cfg inp =
114+ let schemaIssuesPresent = not $ P.null $ schemaIssues inp
115+ breakingChangesPresent = not $ P.null $ breakingChanges inp
116+ nonBreakingChangesPresent = not $ P.null $ nonBreakingChanges inp
117+ unsupportedChangesPresent = not $ P.null $ unsupportedChanges inp
118+ nonBreakingChangesShown = case reportMode cfg of
119+ All -> True
120+ OnlyErrors -> False
121+ builder = buildReport cfg
122+ report =
123+ header 1 "Summary"
124+ <> twoRowTable
125+ ( when'
126+ schemaIssuesPresent
127+ [
128+ ( refOpt schemaIssuesPresent schemaIssuesId "‼️ Schema issues"
129+ , show' $ P.size $ schemaIssues inp
130+ )
131+ ]
132+ ++ [
133+ ( refOpt breakingChangesPresent breakingChangesId "❌ Breaking changes"
134+ , show' $ P.size $ breakingChanges inp
135+ )
136+ ]
137+ ++ when'
138+ nonBreakingChangesShown
139+ [
140+ ( refOpt nonBreakingChangesPresent nonBreakingChangesId "⚠️ Non-breaking changes"
141+ , show' $ P.size $ nonBreakingChanges inp
142+ )
143+ ]
144+ ++ when'
145+ unsupportedChangesPresent
146+ [
147+ ( refOpt unsupportedChangesPresent unsupportedChangesId "❓ Unsupported feature changes"
148+ , show' $ P.size $ unsupportedChanges inp
149+ )
150+ ]
151+ )
152+ <> when'
153+ schemaIssuesPresent
154+ ( header 1 (anchor schemaIssuesId <> "‼️ Schema issues")
155+ <> builder (showErrs $ schemaIssues inp)
156+ )
157+ <> when'
158+ breakingChangesPresent
159+ ( header 1 (anchor breakingChangesId <> "❌ Breaking changes")
160+ <> builder (showErrs $ breakingChanges inp)
161+ )
162+ <> when'
163+ (nonBreakingChangesPresent && nonBreakingChangesShown)
164+ ( header 1 (anchor nonBreakingChangesId <> "⚠️ Non-breaking changes")
165+ <> builder (showErrs $ nonBreakingChanges inp)
166+ )
167+ <> when'
168+ unsupportedChangesPresent
169+ ( header 1 (anchor unsupportedChangesId <> "❓ Unsupported feature changes")
170+ <> builder (showErrs $ unsupportedChanges inp)
171+ )
172+ status =
173+ if
174+ | breakingChangesPresent -> BreakingChanges
175+ | unsupportedChangesPresent -> OnlyUnsupportedChanges
176+ | otherwise -> NoBreakingChanges
177+ in (report, status)
178+ where
179+ anchor :: Text -> Inlines
180+ anchor a = spanWith (a, [], []) mempty
181+
182+ refOpt :: Bool -> Text -> Inlines -> Inlines
183+ refOpt False _ i = i
184+ refOpt True a i = link ("#" <> a) "" i
185+
186+ breakingChangesId, nonBreakingChangesId, unsupportedChangesId, schemaIssuesId :: Text
187+ breakingChangesId = "breaking-changes"
188+ unsupportedChangesId = "unsupported-changes"
189+ nonBreakingChangesId = "non-breaking-changes"
190+ schemaIssuesId = "schema-issues"
191+
192+ when' :: Monoid m => Bool -> m -> m
193+ when' True m = m
194+ when' False _ = mempty
195+
196+showErrs :: forall a. Typeable a => P.PathsPrefixTree Behave AnIssue a -> Report
197+showErrs x@(P.PathsPrefixNode currentIssues _) =
198+ let -- Extract this pattern if more cases like this arise
199+ ( removedPaths :: Maybe (Orientation, [Issue 'APILevel])
200+ , otherIssues :: Set (AnIssue a)
201+ ) = case eqT @a @'APILevel of
202+ Just Refl
203+ | (S.toList -> p@((AnIssue ori _) : _), o) <-
204+ S.partition
205+ ( \((AnIssue _ u)) -> case u of
206+ NoPathsMatched {} -> True
207+ AllPathsFailed {} -> True
208+ )
209+ currentIssues ->
210+ let p' = p <&> (\(AnIssue _ i) -> i)
211+ in (Just (ori, p'), o)
212+ _ -> (Nothing, currentIssues)
213+ issues = singletonBody $ case S.toList otherIssues of
214+ [AnIssue ori i] -> describeIssue ori i
215+ ii -> orderedList $ ii <&> (\(AnIssue ori i) -> describeIssue ori i)
216+ paths = case removedPaths of
217+ Just (ori, ps) -> do
218+ singletonHeader
219+ ( case ori of
220+ Forward -> "Removed paths"
221+ Backward -> "Added paths"
222+ )
223+ $ singletonBody $
224+ bulletList $
225+ ps <&> \case
226+ (NoPathsMatched p) -> para . code $ T.pack p
227+ (AllPathsFailed p) -> para . code $ T.pack p
228+ Nothing -> mempty
229+ rest = unfoldFunctions x (observeJetShowErrs <$> jets) $ \(P.PathsPrefixNode _ subIssues) -> do
230+ flip foldMap subIssues $ \(WrapTypeable (AStep m)) ->
231+ flip foldMap (M.toList m) $ \(bhv, subErrors) ->
232+ if P.null subErrors
233+ then mempty
234+ else singletonHeader (describeBehavior bhv) $ showErrs subErrors
235+ in issues <> paths <> rest
236+
237+unfoldFunctions :: forall m a. (Monoid m, Eq a) => a -> [a -> (m, a)] -> (a -> m) -> m
238+unfoldFunctions initA fs g = unfoldFunctions' initA fs
239+ where
240+ unfoldFunctions' :: a -> [a -> (m, a)] -> m
241+ unfoldFunctions' a [] | a == initA = g a
242+ unfoldFunctions' a [] = unfoldFunctions a fs g
243+ unfoldFunctions' a (f : ff) =
244+ let (m, a') = f a
245+ in unfoldFunctions' a' ff <> m
246+
247+jets :: [ReportJet' Behave (Maybe Inlines)]
248+jets =
249+ unwrapReportJetResult
250+ <$> [ constructReportJet $
251+ curry $ \case
252+ (OfType Object, p@(InPartition _)) -> Just $ describeBehavior p :: Maybe Inlines
253+ _ -> Nothing
254+ , constructReportJet jsonPathJet
255+ , constructReportJet $ \p@(AtPath _) op@(InOperation _) ->
256+ strong (describeBehavior op) <> " " <> describeBehavior p :: Inlines
257+ , constructReportJet $ \(WithStatusCode c) ResponsePayload PayloadSchema ->
258+ "⬅️☁️ JSON Response – " <> str (T.pack . show $ c) :: Inlines
259+ , constructReportJet $ \InRequest InPayload PayloadSchema -> "➡️☁️ JSON Request" :: Inlines
260+ ]
261+ where
262+ unwrapReportJetResult :: ReportJetResult Behave x -> ReportJet' Behave x
263+ unwrapReportJetResult (Pure _) = error "There really shouldn't be any results here."
264+ unwrapReportJetResult (Free f) = f
265+
266+ jsonPathJet ::
267+ NonEmpty
268+ ( Union
269+ '[ Behave 'SchemaLevel 'TypedSchemaLevel
270+ , Behave 'TypedSchemaLevel 'SchemaLevel
271+ ]
272+ ) ->
273+ Inlines
274+ jsonPathJet x = code $ "$" <> showParts (NE.toList x)
275+ where
276+ showParts ::
277+ [ Union
278+ '[ Behave 'SchemaLevel 'TypedSchemaLevel
279+ , Behave 'TypedSchemaLevel 'SchemaLevel
280+ ]
281+ ] ->
282+ Text
283+ showParts [] = mempty
284+ showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion (InProperty _)) : _)) = showParts xs
285+ showParts (SingletonUnion (OfType Object) : xs@((SingletonUnion InAdditionalProperty) : _)) = showParts xs
286+ showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion InItems : _)) = showParts xs
287+ showParts (SingletonUnion (OfType Array) : xs@(SingletonUnion (InItem _) : _)) = showParts xs
288+ showParts (y : ys) =
289+ ( (\(OfType t) -> "(" <> describeJSONType t <> ")")
290+ @@> ( \case
291+ InItems -> "[*]"
292+ InItem i -> "[" <> T.pack (show i) <> "]"
293+ InProperty p -> "." <> p
294+ InAdditionalProperty -> ".*"
295+ )
296+ @@> typesExhausted
297+ )
298+ y
299+ <> showParts ys
300+
301+observeJetShowErrs ::
302+ ReportJet' Behave (Maybe Inlines) ->
303+ P.PathsPrefixTree Behave AnIssue a ->
304+ (Report, P.PathsPrefixTree Behave AnIssue a)
305+observeJetShowErrs jet p = case observeJetShowErrs' jet p of
306+ Just m -> m
307+ Nothing -> (mempty, p)
308+
309+observeJetShowErrs' ::
310+ forall a.
311+ ReportJet' Behave (Maybe Inlines) ->
312+ P.PathsPrefixTree Behave AnIssue a ->
313+ Maybe (Report, P.PathsPrefixTree Behave AnIssue a)
314+observeJetShowErrs' (ReportJet jet) (P.PathsPrefixNode currentIssues subIssues) =
315+ let results =
316+ subIssues >>= \(WrapTypeable (AStep m)) ->
317+ M.toList m <&> \(bhv, subErrs) ->
318+ maybe (Left $ embed (step bhv) subErrs) Right . listToMaybe $
319+ jet @_ @_ @[] bhv
320+ & mapMaybe
321+ ( \case
322+ Free jet' -> fmap (embed $ step bhv) <$> observeJetShowErrs' jet' subErrs
323+ Pure (Just h) ->
324+ if P.null subErrs
325+ then Just mempty
326+ else Just (singletonHeader h (showErrs subErrs), mempty)
327+ Pure Nothing -> Nothing
328+ )
329+ in (fmap . fmap) (PathsPrefixNode currentIssues mempty <>) $
330+ if any isRight results
331+ then
332+ Just $
333+ foldMap
334+ ( \case
335+ Left e -> (mempty, e)
336+ Right m -> m
337+ )
338+ results
339+ else Nothing
340+
341+data Report = Report {headers :: OMap Inlines Report, body :: Blocks}
342+ deriving stock (Generic)
343+
344+instance Semigroup Report where
345+ (Report headers1 b1) <> (Report headers2 b2) = Report (OM.unionWithL (const (<>)) headers1 headers2) (b1 <> b2)
346+
347+instance Monoid Report where
348+ mempty = Report OM.empty mempty
349+
350+buildReport :: ReportConfig -> Report -> Blocks
351+buildReport cfg = case treeStyle cfg of
352+ HeadersTreeStyle -> headerStyleBuilder 2
353+ FoldingBlockquotesTreeStyle -> foldingStyleBuilder
354+ where
355+ headerStyleBuilder :: HeaderLevel -> Report -> Blocks
356+ headerStyleBuilder level rprt =
357+ body rprt
358+ <> foldOMapWithKey
359+ (headers rprt)
360+ ( \k v ->
361+ header level k <> subBuilder v
362+ )
363+ where
364+ subBuilder = headerStyleBuilder (level + 1)
365+
366+ foldingStyleBuilder :: Report -> Blocks
367+ foldingStyleBuilder rprt =
368+ body rprt
369+ <> foldOMapWithKey
370+ (headers rprt)
371+ ( \k v ->
372+ if (OM.size . headers $ rprt) < 2
373+ then para k <> blockQuote (subBuilder v)
374+ else
375+ rawHtml "<details>"
376+ <> rawHtml "<summary>"
377+ <> plain k
378+ <> rawHtml "</summary>"
379+ <> blockQuote (subBuilder v)
380+ <> rawHtml "</details>"
381+ )
382+ where
383+ subBuilder = foldingStyleBuilder
384+
385+ rawHtml = rawBlock "html"
386+
387+type HeaderLevel = Int
388+
389+singletonHeader :: Inlines -> Report -> Report
390+singletonHeader i b = Report (OM.singleton (i, b)) mempty
391+
392+singletonBody :: Blocks -> Report
393+singletonBody = Report OM.empty
394+
395+show' :: Show x => x -> Inlines
396+show' = str . T.pack . show
397+
398+foldOMapWithKey :: Monoid m => OMap k v -> (k -> v -> m) -> m
399+foldOMapWithKey m f = foldMap (uncurry f) $ OM.assocs m
src/Data/OpenApi/Compare/Report/Html/Template.hsnew file+39
@@ -0,0 +1,39 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+module Data.OpenApi.Compare.Report.Html.Template
4+ ( template,
5+ )
6+where
7+
8+import Control.Monad.Identity
9+import Data.ByteString (ByteString)
10+import Data.FileEmbed
11+import Data.Text (Text)
12+import qualified Data.Text.Encoding as T
13+import Text.DocTemplates
14+
15+template :: Template Text
16+template =
17+ either error id . runIdentity . compileTemplate "" $
18+ "<!doctype html>\
19+ \<html lang=\"en\">\
20+ \<head>\
21+ \<style>"
22+ <> T.decodeUtf8 awsmCss
23+ <> "</style>\
24+ \<meta charset=\"utf-8\">\
25+ \<title></title>\
26+ \<meta name=\"description\" content=\"\">\
27+ \<meta name=\"generator\" content=\"CompaREST\" />\
28+ \<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\" />\
29+ \</head>\
30+ \<body>\
31+ \<header><h1>CompaREST</h1></header>\
32+ \<main>\
33+ \$body$\
34+ \</main>\
35+ \</body>\
36+ \</html>"
37+
38+awsmCss :: ByteString
39+awsmCss = $(makeRelativeToProject "css/awsm.min.css" >>= embedFile)
src/Data/OpenApi/Compare/Report/Jet.hsnew file+67
@@ -0,0 +1,67 @@
1+module Data.OpenApi.Compare.Report.Jet
2+ ( ReportJet (..),
3+ ReportJet',
4+ ConstructReportJet (..),
5+ ReportJetResult,
6+ )
7+where
8+
9+import Control.Applicative
10+import Control.Monad.Free
11+import Data.List.NonEmpty
12+import qualified Data.List.NonEmpty as NE
13+import Data.OpenUnion
14+import Data.OpenUnion.Extra
15+import Data.Typeable
16+import Text.Pandoc.Builder
17+
18+-- | A "jet" is a way of simplifying expressions from "outside". The "jetted"
19+-- expressions should still be completely valid and correct without the jets.
20+-- Jets just make the expression more "optimized" by identifying patterns and
21+-- replacing the expressions with "better" ones that have the same sematics.
22+--
23+-- The term "jet" in this context was introduced in the Urbit project:
24+-- https://urbit.org/docs/vere/jetting/
25+--
26+-- The pattern fits well for simplifying 'Behavior' tree paths.
27+class ConstructReportJet x f where
28+ constructReportJet :: x -> ReportJetResult f (Maybe Inlines)
29+
30+instance (ConstructReportJet b f, JetArg a) => ConstructReportJet (a -> b) f where
31+ constructReportJet f = Free (fmap f <$> consumeJetArg @a) >>= constructReportJet
32+
33+instance ConstructReportJet (Maybe Inlines) f where
34+ constructReportJet x = Pure x
35+
36+instance ConstructReportJet Inlines f where
37+ constructReportJet x = Pure $ Just x
38+
39+class JetArg a where
40+ consumeJetArg :: ReportJet' f a
41+
42+instance Typeable (f a b) => JetArg (f a b) where
43+ consumeJetArg =
44+ ReportJet $ \(x :: x) ->
45+ case eqT @(f a b) @x of
46+ Nothing -> empty
47+ Just Refl -> pure $ Pure x
48+
49+instance TryLiftUnion xs => JetArg (Union xs) where
50+ consumeJetArg = ReportJet $ fmap Pure . tryLiftUnion
51+
52+instance JetArg x => JetArg (NonEmpty x) where
53+ consumeJetArg =
54+ let (ReportJet f) = (consumeJetArg @x)
55+ in ReportJet $ \a -> do
56+ u <- f a
57+ pure (u >>= \y -> Free $ fmap (NE.cons y) <$> consumeJetArg)
58+ <|> pure (pure <$> u)
59+
60+type ReportJetResult f = Free (ReportJet f)
61+
62+-- Not a true 'Applicative'
63+newtype ReportJet f x
64+ = ReportJet (forall a b m. (Typeable (f a b), Alternative m, Monad m) => f a b -> m x)
65+ deriving stock (Functor)
66+
67+type ReportJet' f a = ReportJet f (Free (ReportJet f) a)
src/Data/OpenApi/Compare/Run.hsnew file+31
@@ -0,0 +1,31 @@
1+module Data.OpenApi.Compare.Run
2+ ( runChecker,
3+ runReport,
4+ module Data.OpenApi.Compare.Report,
5+ )
6+where
7+
8+import Data.HList
9+import Data.OpenApi (OpenApi)
10+import Data.OpenApi.Compare.Paths
11+import Data.OpenApi.Compare.Report
12+import Data.OpenApi.Compare.Subtree
13+import Data.OpenApi.Compare.Validate.OpenApi ()
14+import Text.Pandoc.Builder
15+
16+runChecker :: (OpenApi, OpenApi) -> CheckerOutput
17+runChecker (client, server) =
18+ CheckerOutput
19+ { forwardChanges = run client server
20+ , backwardChanges = run server client
21+ }
22+ where
23+ toPC p c =
24+ ProdCons
25+ { producer = traced (step ClientSchema) p
26+ , consumer = traced (step ServerSchema) c
27+ }
28+ run p c = either id mempty . runCompatFormula . checkCompatibility Root HNil $ toPC p c
29+
30+runReport :: ReportConfig -> (OpenApi, OpenApi) -> (Blocks, ReportStatus)
31+runReport cfg = generateReport cfg . segregateIssues . runChecker
src/Data/OpenApi/Compare/Subtree.hsnew file+364
@@ -0,0 +1,364 @@
1+{-# OPTIONS_GHC -Wno-orphans #-}
2+
3+module Data.OpenApi.Compare.Subtree
4+ ( Steppable (..),
5+ Step (..),
6+ TraceRoot,
7+ Trace,
8+ Traced,
9+ Traced',
10+ pattern Traced,
11+ traced,
12+ retraced,
13+ stepTraced,
14+ Subtree (..),
15+ checkCompatibility,
16+ checkSubstructure,
17+ CompatM (..),
18+ CompatFormula',
19+ SemanticCompatFormula,
20+ ProdCons (..),
21+ orientProdCons,
22+ swapProdCons,
23+ runCompatFormula,
24+ issueAt,
25+ anItem,
26+ anIssue,
27+ invertIssueOrientation,
28+ invertIssueOrientationP,
29+ embedFormula,
30+ anyOfAt,
31+ clarifyIssue,
32+ structuralIssue,
33+
34+ -- * Structural helpers
35+ structuralMaybe,
36+ structuralMaybeWith,
37+ structuralEq,
38+ iohmStructural,
39+ iohmStructuralWith,
40+ structuralList,
41+
42+ -- * Reexports
43+ (>>>),
44+ (<<<),
45+ extract,
46+ ask,
47+ local,
48+ step,
49+ Typeable,
50+ )
51+where
52+
53+import Control.Comonad.Env
54+import Control.Monad.Identity
55+import Control.Monad.State
56+import Data.Foldable
57+import Data.Functor.Compose
58+import Data.HList
59+import qualified Data.HashMap.Strict.InsOrd as IOHM
60+import Data.Hashable
61+import Data.Kind
62+import Data.OpenApi
63+import Data.OpenApi.Compare.Behavior
64+import Data.OpenApi.Compare.Formula
65+import Data.OpenApi.Compare.Memo
66+import Data.OpenApi.Compare.Paths
67+import qualified Data.OpenApi.Compare.PathsPrefixTree as P
68+import qualified Data.Set as S
69+import Data.Typeable
70+
71+class
72+ (Typeable Step, Typeable a, Typeable b, Ord (Step a b), Show (Step a b)) =>
73+ Steppable (a :: Type) (b :: Type)
74+ where
75+ -- | How to get from an @a@ node to a @b@ node
76+ data Step a b :: Type
77+
78+data TraceRoot
79+
80+instance Steppable TraceRoot OpenApi where
81+ data Step TraceRoot OpenApi
82+ = ClientSchema
83+ | ServerSchema
84+ deriving stock (Eq, Ord, Show)
85+
86+type Trace = Paths Step TraceRoot
87+
88+type instance AdditionalQuiverConstraints Step _ _ = ()
89+
90+type Traced' a b = Env (Trace a) b
91+
92+type Traced a = Traced' a a
93+
94+pattern Traced :: Trace a -> b -> Traced' a b
95+pattern Traced t x = EnvT t (Identity x)
96+
97+{-# COMPLETE Traced #-}
98+
99+traced :: Trace a -> a -> Traced a
100+traced = env
101+
102+retraced :: (Trace a -> Trace a') -> Traced' a b -> Traced' a' b
103+retraced f (Traced a b) = Traced (f a) b
104+
105+stepTraced :: Steppable a a' => Step a a' -> Traced' a b -> Traced' a' b
106+stepTraced s = retraced (>>> step s)
107+
108+data ProdCons a = ProdCons
109+ { producer :: a
110+ , consumer :: a
111+ }
112+ deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable)
113+
114+orientProdCons :: Orientation -> ProdCons x -> ProdCons x
115+orientProdCons Forward x = x
116+orientProdCons Backward (ProdCons p c) = ProdCons c p
117+
118+swapProdCons ::
119+ SwapEnvRoles xs =>
120+ (HList xs -> ProdCons x -> CompatFormula' q AnIssue r a) ->
121+ (HList xs -> ProdCons x -> CompatFormula' q AnIssue r a)
122+swapProdCons f e (ProdCons p c) =
123+ invertIssueOrientation $
124+ f (swapEnvRoles e) (ProdCons c p)
125+{-# INLINE swapProdCons #-}
126+
127+type family IsProdCons (x :: Type) :: Bool where
128+ IsProdCons (ProdCons _) = 'True
129+ IsProdCons _ = 'False
130+
131+type SwapEnvElementRoles x = SwapEnvElementRoles' x (IsProdCons x)
132+
133+class IsProdCons x ~ f => SwapEnvElementRoles' (x :: Type) f where
134+ swapEnvElementRoles :: x -> x
135+
136+instance SwapEnvElementRoles' (ProdCons x) 'True where
137+ swapEnvElementRoles (ProdCons p c) = ProdCons c p
138+
139+instance IsProdCons x ~ 'False => SwapEnvElementRoles' x 'False where
140+ swapEnvElementRoles = id
141+
142+class SwapEnvRoles xs where
143+ swapEnvRoles :: HList xs -> HList xs
144+
145+instance SwapEnvRoles '[] where
146+ swapEnvRoles = id
147+
148+instance (SwapEnvElementRoles x, SwapEnvRoles xs) => SwapEnvRoles (x ': xs) where
149+ swapEnvRoles (HCons x xs) = HCons (swapEnvElementRoles x) (swapEnvRoles xs)
150+
151+instance Applicative ProdCons where
152+ pure x = ProdCons x x
153+ ProdCons fp fc <*> ProdCons xp xc = ProdCons (fp xp) (fc xc)
154+
155+newtype CompatM a = CompatM
156+ { unCompatM ::
157+ StateT (MemoState VarRef) Identity a
158+ }
159+ deriving newtype
160+ ( Functor
161+ , Applicative
162+ , Monad
163+ , MonadState (MemoState VarRef)
164+ )
165+
166+type CompatFormula' q f r = Compose CompatM (FormulaF q f r)
167+
168+type SemanticCompatFormula = CompatFormula' Behave AnIssue 'APILevel
169+
170+type StructuralCompatFormula = CompatFormula' VoidQuiver Proxy ()
171+
172+data VoidQuiver a b
173+
174+deriving stock instance Eq (VoidQuiver a b)
175+
176+type instance AdditionalQuiverConstraints VoidQuiver _ _ = ()
177+
178+deriving stock instance Ord (VoidQuiver a b)
179+
180+deriving stock instance Show (VoidQuiver a b)
181+
182+class (Typeable t, Issuable (SubtreeLevel t)) => Subtree (t :: Type) where
183+ type CheckEnv t :: [Type]
184+ type SubtreeLevel t :: BehaviorLevel
185+
186+ checkStructuralCompatibility ::
187+ HList (CheckEnv t) ->
188+ ProdCons (Traced t) ->
189+ StructuralCompatFormula ()
190+
191+ checkSemanticCompatibility ::
192+ HList (CheckEnv t) ->
193+ Behavior (SubtreeLevel t) ->
194+ ProdCons (Traced t) ->
195+ SemanticCompatFormula ()
196+
197+{-# WARNING checkStructuralCompatibility "You should not be calling this directly. Use 'checkSubstructure'" #-}
198+
199+{-# WARNING checkSemanticCompatibility "You should not be calling this directly. Use 'checkCompatibility'" #-}
200+
201+checkCompatibility ::
202+ forall t xs.
203+ (ReassembleHList xs (CheckEnv t), Subtree t) =>
204+ Behavior (SubtreeLevel t) ->
205+ HList xs ->
206+ ProdCons (Traced t) ->
207+ SemanticCompatFormula ()
208+checkCompatibility bhv e = memo bhv SemanticMemoKey $ \pc ->
209+ case runCompatFormula $ checkSubstructure e pc of
210+ Left _ -> checkSemanticCompatibility (reassemble e) bhv pc
211+ Right () -> pure ()
212+{-# INLINE checkCompatibility #-}
213+
214+checkSubstructure ::
215+ (ReassembleHList xs (CheckEnv t), Subtree t) =>
216+ HList xs ->
217+ ProdCons (Traced t) ->
218+ StructuralCompatFormula ()
219+checkSubstructure e = memo Root StructuralMemoKey $ checkStructuralCompatibility (reassemble e)
220+{-# INLINE checkSubstructure #-}
221+
222+structuralMaybe ::
223+ (Subtree a, ReassembleHList xs (CheckEnv a)) =>
224+ HList xs ->
225+ ProdCons (Maybe (Traced a)) ->
226+ StructuralCompatFormula ()
227+structuralMaybe e = structuralMaybeWith (checkSubstructure e)
228+{-# INLINE structuralMaybe #-}
229+
230+structuralMaybeWith ::
231+ (ProdCons a -> StructuralCompatFormula ()) ->
232+ ProdCons (Maybe a) ->
233+ StructuralCompatFormula ()
234+structuralMaybeWith f (ProdCons (Just a) (Just b)) = f $ ProdCons a b
235+structuralMaybeWith _ (ProdCons Nothing Nothing) = pure ()
236+structuralMaybeWith _ _ = structuralIssue
237+{-# INLINE structuralMaybeWith #-}
238+
239+structuralList ::
240+ (Subtree a, ReassembleHList xs (CheckEnv a)) =>
241+ HList xs ->
242+ ProdCons [Traced a] ->
243+ StructuralCompatFormula ()
244+structuralList _ (ProdCons [] []) = pure ()
245+structuralList e (ProdCons (a : aa) (b : bb)) = do
246+ checkSubstructure e $ ProdCons a b
247+ structuralList e $ ProdCons aa bb
248+ pure ()
249+structuralList _ _ = structuralIssue
250+{-# INLINE structuralList #-}
251+
252+structuralEq :: (Eq a, Comonad w) => ProdCons (w a) -> StructuralCompatFormula ()
253+structuralEq (ProdCons a b) = if extract a == extract b then pure () else structuralIssue
254+{-# INLINE structuralEq #-}
255+
256+iohmStructural ::
257+ (ReassembleHList (k ': xs) (CheckEnv v), Ord k, Subtree v, Hashable k, Typeable k, Show k) =>
258+ HList xs ->
259+ ProdCons (Traced (IOHM.InsOrdHashMap k v)) ->
260+ StructuralCompatFormula ()
261+iohmStructural e =
262+ iohmStructuralWith (\k -> checkSubstructure (k `HCons` e))
263+{-# INLINE iohmStructural #-}
264+
265+instance (Typeable k, Typeable v, Ord k, Show k) => Steppable (IOHM.InsOrdHashMap k v) v where
266+ data Step (IOHM.InsOrdHashMap k v) v = InsOrdHashMapKeyStep k
267+ deriving stock (Eq, Ord, Show)
268+
269+iohmStructuralWith ::
270+ (Ord k, Hashable k, Typeable k, Typeable v, Show k) =>
271+ (k -> ProdCons (Traced v) -> StructuralCompatFormula ()) ->
272+ ProdCons (Traced (IOHM.InsOrdHashMap k v)) ->
273+ StructuralCompatFormula ()
274+iohmStructuralWith f pc = do
275+ let ProdCons pEKeys cEKeys = S.fromList . IOHM.keys . extract <$> pc
276+ if pEKeys == cEKeys
277+ then
278+ for_
279+ pEKeys
280+ ( \eKey ->
281+ f eKey $ stepTraced (InsOrdHashMapKeyStep eKey) . fmap (IOHM.lookupDefault (error "impossible") eKey) <$> pc
282+ )
283+ else structuralIssue
284+{-# INLINE iohmStructuralWith #-}
285+
286+runCompatFormula ::
287+ CompatFormula' q f r a ->
288+ Either (P.PathsPrefixTree q f r) a
289+runCompatFormula (Compose f) =
290+ calculate . runIdentity . runMemo 0 . unCompatM $ f
291+{-# INLINE runCompatFormula #-}
292+
293+embedFormula :: Paths q r l -> CompatFormula' q f l a -> CompatFormula' q f r a
294+embedFormula bhv (Compose x) = Compose $ mapErrors (P.embed bhv) <$> x
295+
296+issueAt :: Issuable l => Paths q r l -> Issue l -> CompatFormula' q AnIssue r a
297+issueAt xs issue = Compose $ pure $ anError $ AnItem xs $ anIssue issue
298+{-# INLINE issueAt #-}
299+
300+anIssue :: Issuable l => Issue l -> AnIssue l
301+anIssue = AnIssue Forward
302+{-# INLINE anIssue #-}
303+
304+anItem :: AnItem q AnIssue r -> CompatFormula' q AnIssue r a
305+anItem = Compose . pure . anError
306+{-# INLINE anItem #-}
307+
308+invertIssueOrientation :: CompatFormula' q AnIssue r a -> CompatFormula' q AnIssue r a
309+invertIssueOrientation (Compose x) =
310+ Compose $ mapErrors invertIssueOrientationP <$> x
311+
312+invertIssueOrientationP :: P.PathsPrefixTree q AnIssue r -> P.PathsPrefixTree q AnIssue r
313+invertIssueOrientationP = P.map (\(AnIssue ori i) -> AnIssue (toggleOrientation ori) i)
314+
315+structuralIssue :: StructuralCompatFormula a
316+structuralIssue = Compose $ pure $ anError $ AnItem Root Proxy
317+
318+anyOfAt ::
319+ Issuable l =>
320+ Paths q r l ->
321+ Issue l ->
322+ [CompatFormula' q AnIssue r a] ->
323+ CompatFormula' q AnIssue r a
324+anyOfAt _ _ [x] = x
325+anyOfAt xs issue fs =
326+ Compose $ (`eitherOf` AnItem xs (anIssue issue)) <$> traverse getCompose fs
327+
328+-- | If the given formula contains any issues, add another issue on top. Otherwise succeed.
329+clarifyIssue ::
330+ AnItem q AnIssue r ->
331+ CompatFormula' q AnIssue r a ->
332+ CompatFormula' q AnIssue r a
333+clarifyIssue item f =
334+ Compose ((`eitherOf` item) <$> pure <$> getCompose f) *> f
335+
336+fixpointKnot ::
337+ MonadState (MemoState VarRef) m =>
338+ KnotTier (FormulaF q f r ()) VarRef m
339+fixpointKnot =
340+ KnotTier
341+ { onKnotFound = modifyMemoNonce succ
342+ , onKnotUsed = \i -> pure $ variable i
343+ , tieKnot = \i x -> pure $ maxFixpoint i x
344+ }
345+
346+memo ::
347+ (Typeable (l :: k), Typeable q, Typeable f, Typeable k, Typeable a) =>
348+ Paths q r l ->
349+ MemoKey ->
350+ (ProdCons (Traced a) -> CompatFormula' q f r ()) ->
351+ (ProdCons (Traced a) -> CompatFormula' q f r ())
352+memo bhv k f pc = Compose $ do
353+ formula' <-
354+ memoWithKnot
355+ fixpointKnot
356+ ( do
357+ formula <- getCompose $ f pc
358+ pure $ mapErrors (P.takeSubtree bhv) formula
359+ )
360+ (k, ask <$> pc)
361+ pure $ mapErrors (P.embed bhv) formula'
362+
363+data MemoKey = SemanticMemoKey | StructuralMemoKey
364+ deriving stock (Eq, Ord)
src/OpenAPI/Checker/Validate/Header.hs → src/Data/OpenApi/Compare/Validate/Header.hsrenamed+15−11
@@ -1,6 +1,6 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.Validate.Header
3+module Data.OpenApi.Compare.Validate.Header
44 (
55 )
66where
@@ -9,10 +9,10 @@ import Data.Foldable
99import Data.Functor
1010import Data.Maybe
1111import Data.OpenApi
12−import OpenAPI.Checker.Behavior
13−import OpenAPI.Checker.References ()
14−import OpenAPI.Checker.Subtree
15−import OpenAPI.Checker.Validate.Schema ()
12+import Data.OpenApi.Compare.Behavior
13+import Data.OpenApi.Compare.References ()
14+import Data.OpenApi.Compare.Subtree
15+import Data.OpenApi.Compare.Validate.Schema ()
1616import Text.Pandoc.Builder
1717
1818instance Subtree Header where
@@ -34,7 +34,7 @@ instance Subtree Header where
3434 for_ (tracedSchema c) $ \consRef ->
3535 case tracedSchema p of
3636 Nothing -> issueAt beh HeaderSchemaRequired
37− Just prodRef -> checkCompatibility env (beh >>> step InSchema) (ProdCons prodRef consRef)
37+ Just prodRef -> checkCompatibility (beh >>> step InSchema) env (ProdCons prodRef consRef)
3838 pure ()
3939
4040instance Steppable Header (Referenced Schema) where
@@ -50,13 +50,17 @@ instance Issuable 'HeaderLevel where
5050 | NonEmptyHeaderRequired
5151 | HeaderSchemaRequired
5252 deriving stock (Eq, Ord, Show)
53− issueIsUnsupported _ = False
54− describeIssue RequiredHeaderMissing = para "Header expected, but missing."
55− describeIssue NonEmptyHeaderRequired = para "Empty header not allowed."
56− describeIssue HeaderSchemaRequired = para "Expected header schema, but it is not present."
53+ issueKind = \case
54+ HeaderSchemaRequired -> ProbablyIssue -- catch-all schema?
55+ _ -> CertainIssue
56+ describeIssue Forward RequiredHeaderMissing = para "Header has become required."
57+ describeIssue Backward RequiredHeaderMissing = para "Header is no longer required."
58+ describeIssue Forward NonEmptyHeaderRequired = para "The header does not allow empty values anymore."
59+ describeIssue Backward NonEmptyHeaderRequired = para "The header now allows empty values."
60+ describeIssue _ HeaderSchemaRequired = para "Expected header schema, but it is not present."
5761
5862instance Behavable 'HeaderLevel 'SchemaLevel where
5963 data Behave 'HeaderLevel 'SchemaLevel
6064 = InSchema
6165 deriving stock (Eq, Ord, Show)
62− describeBehaviour InSchema = "JSON Schema"
66+ describeBehavior InSchema = "JSON Schema"
src/OpenAPI/Checker/Validate/Link.hs → src/Data/OpenApi/Compare/Validate/Link.hsrenamed+7−7
@@ -1,10 +1,10 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.Validate.Link () where
3+module Data.OpenApi.Compare.Validate.Link () where
44
55import Data.OpenApi
6−import OpenAPI.Checker.Behavior
7−import OpenAPI.Checker.Subtree
6+import Data.OpenApi.Compare.Behavior
7+import Data.OpenApi.Compare.Subtree
88import Text.Pandoc.Builder
99
1010instance Subtree Link where
@@ -16,7 +16,7 @@ instance Subtree Link where
1616instance Issuable 'LinkLevel where
1717 data Issue 'LinkLevel
1818 = LinksUnsupported
19− deriving (Eq, Ord, Show)
20− issueIsUnsupported = \case
21− LinksUnsupported -> True
22− describeIssue LinksUnsupported = para "OpenApi Diff does not currently support Link Objects."
19+ deriving stock (Eq, Ord, Show)
20+ issueKind = \case
21+ LinksUnsupported -> Unsupported
22+ describeIssue _ LinksUnsupported = para "CompaREST does not currently support Link Objects."
src/OpenAPI/Checker/Validate/MediaTypeObject.hs → src/Data/OpenApi/Compare/Validate/MediaTypeObject.hsrenamed+41−35
@@ -1,26 +1,26 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.Validate.MediaTypeObject
4− ( Issue (..)
5− , Behave (..)
3+module Data.OpenApi.Compare.Validate.MediaTypeObject
4+ ( Issue (..),
5+ Behave (..),
66 )
77where
88
9−import Control.Lens hiding (para)
109import Data.Foldable as F
10+import Data.Functor
1111import Data.HList
1212import Data.HashMap.Strict.InsOrd as IOHM
1313import Data.Map.Strict as M
1414import Data.OpenApi
15+import Data.OpenApi.Compare.Behavior
16+import Data.OpenApi.Compare.Subtree
17+import Data.OpenApi.Compare.Validate.Header ()
18+import Data.OpenApi.Compare.Validate.Products
19+import Data.OpenApi.Compare.Validate.Schema ()
1520import Data.String
1621import Data.Text (Text)
1722import qualified Data.Text as T
1823import Network.HTTP.Media (MediaType, mainType, subType)
19−import OpenAPI.Checker.Behavior
20−import OpenAPI.Checker.Subtree
21−import OpenAPI.Checker.Validate.Header ()
22−import OpenAPI.Checker.Validate.Products
23−import OpenAPI.Checker.Validate.Schema ()
2424import Text.Pandoc.Builder
2525
2626tracedSchema :: Traced MediaTypeObject -> Maybe (Traced (Referenced Schema))
@@ -37,20 +37,21 @@ instance Issuable 'PayloadLevel where
3737 = MediaTypeSchemaRequired
3838 | MediaEncodingMissing Text
3939 | EncodingNotSupported
40− deriving (Eq, Ord, Show)
41− issueIsUnsupported = \case
42− EncodingNotSupported -> True
43− _ -> False
40+ deriving stock (Eq, Ord, Show)
41+ issueKind = \case
42+ EncodingNotSupported -> Unsupported
43+ _ -> CertainIssue
4444
45− describeIssue MediaTypeSchemaRequired = para "Media type expected, but was not specified."
46− describeIssue (MediaEncodingMissing enc) = para $ "Media encoding " <> str enc <> " expected, but was not specified."
47− describeIssue EncodingNotSupported = para "OpenApi Diff does not currently support media encodings other than JSON."
45+ describeIssue _ MediaTypeSchemaRequired = para "Media type expected, but was not specified."
46+ describeIssue Forward (MediaEncodingMissing enc) = para $ "Media encoding " <> str enc <> " has been removed."
47+ describeIssue Backward (MediaEncodingMissing enc) = para $ "Media encoding " <> str enc <> " added."
48+ describeIssue _ EncodingNotSupported = para "CompaREST does not currently support media encodings other than JSON."
4849
4950instance Behavable 'PayloadLevel 'SchemaLevel where
5051 data Behave 'PayloadLevel 'SchemaLevel
5152 = PayloadSchema
52− deriving (Eq, Ord, Show)
53− describeBehaviour PayloadSchema = "JSON Schema"
53+ deriving stock (Eq, Ord, Show)
54+ describeBehavior PayloadSchema = "JSON Schema"
5455
5556instance Subtree MediaTypeObject where
5657 type SubtreeLevel MediaTypeObject = 'PayloadLevel
@@ -78,7 +79,7 @@ instance Subtree MediaTypeObject where
7879 case tracedSchema p of
7980 Nothing -> issueAt beh MediaTypeSchemaRequired
8081 Just prodRef ->
81− checkCompatibility env (beh >>> step PayloadSchema) $
82+ checkCompatibility (beh >>> step PayloadSchema) env $
8283 ProdCons prodRef consRef
8384 pure ()
8485 where
@@ -98,7 +99,7 @@ instance Subtree MediaTypeObject where
9899 in checkProducts
99100 beh
100101 MediaEncodingMissing
101− (const $ checkCompatibility env beh)
102+ (const $ checkCompatibility beh env)
102103 encProdCons
103104
104105instance Subtree Encoding where
@@ -118,46 +119,51 @@ instance Subtree Encoding where
118119
119120 -- FIXME: Support only JSON body for now. Then Encoding is checked only for
120121 -- multipart/form-url-encoded
121− -- https://github.com/typeable/openapi-diff/issues/54
122+ -- #54
122123 checkSemanticCompatibility _env beh _pc =
123124 issueAt beh EncodingNotSupported
124125
125126instance Steppable MediaTypeObject (Referenced Schema) where
126127 data Step MediaTypeObject (Referenced Schema) = MediaTypeSchema
127− deriving (Eq, Ord, Show)
128+ deriving stock (Eq, Ord, Show)
128129
129130instance Steppable MediaTypeObject (Definitions Encoding) where
130131 data Step MediaTypeObject (Definitions Encoding) = MediaTypeEncodingMapping
131− deriving (Eq, Ord, Show)
132+ deriving stock (Eq, Ord, Show)
132133
133134instance Steppable MediaTypeObject Encoding where
134135 data Step MediaTypeObject Encoding = MediaTypeParamEncoding Text
135− deriving (Eq, Ord, Show)
136+ deriving stock (Eq, Ord, Show)
136137
137138instance Steppable Encoding (Definitions (Referenced Header)) where
138139 data Step Encoding (Definitions (Referenced Header)) = EncodingHeaderStep
139− deriving (Eq, Ord, Show)
140+ deriving stock (Eq, Ord, Show)
140141
141142instance Behavable 'OperationLevel 'ResponseLevel where
142143 data Behave 'OperationLevel 'ResponseLevel
143144 = WithStatusCode HttpStatusCode
144145 deriving stock (Eq, Ord, Show)
145− describeBehaviour (WithStatusCode c) = "Response code " <> (fromString . show $ c)
146+ describeBehavior (WithStatusCode c) = "Response code " <> (fromString . show $ c)
146147
147148instance Issuable 'OperationLevel where
148149 data Issue 'OperationLevel
149− = ResponseCodeNotFound HttpStatusCode
150+ = ConsumerDoesntHaveResponseCode HttpStatusCode
150151 | ParamNotMatched Text
151152 | PathFragmentNotMatched Int
152153 | NoRequestBody
153154 deriving stock (Eq, Ord, Show)
154− issueIsUnsupported = \case
155− _ -> False
156− describeIssue (ResponseCodeNotFound c) =
157− para $ "Reponse code " <> (str . T.pack . show $ c) <> " is not supported."
158− describeIssue (ParamNotMatched param) =
159− para $ "Parameter " <> str param <> " is not supported."
160− describeIssue (PathFragmentNotMatched i) =
155+ issueKind = \case
156+ _ -> CertainIssue
157+ describeIssue Forward (ConsumerDoesntHaveResponseCode c) =
158+ para $ "Response code " <> (str . T.pack . show $ c) <> " has been removed."
159+ describeIssue Backward (ConsumerDoesntHaveResponseCode c) =
160+ para $ "Response code " <> (str . T.pack . show $ c) <> " has been added."
161+ describeIssue Forward (ParamNotMatched param) =
162+ para $ "Parameter " <> code param <> " has become required."
163+ describeIssue Backward (ParamNotMatched param) =
164+ para $ "Parameter " <> code param <> " is no longer required."
165+ describeIssue _ (PathFragmentNotMatched i) =
161166 -- TODO: Indices are meaningless in this context. Replace with a better error.
162167 para $ "Path fragment " <> (str . T.pack . show $ i) <> " not matched."
163− describeIssue NoRequestBody = para "Request body not specified."
168+ describeIssue Forward NoRequestBody = para "Request body has been added."
169+ describeIssue Backward NoRequestBody = para "Request body has been removed."
src/OpenAPI/Checker/Validate/OAuth2Flows.hs → src/Data/OpenApi/Compare/Validate/OAuth2Flows.hsrenamed+59−46
@@ -1,9 +1,9 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.Validate.OAuth2Flows
4− ( Step (..)
5− , Issue (..)
6− , Behave (..)
3+module Data.OpenApi.Compare.Validate.OAuth2Flows
4+ ( Step (..),
5+ Issue (..),
6+ Behave (..),
77 )
88where
99
@@ -12,13 +12,13 @@ import Data.Function
1212import Data.Functor
1313import qualified Data.HashMap.Strict.InsOrd as IOHM
1414import Data.OpenApi
15+import Data.OpenApi.Compare.Behavior
16+import Data.OpenApi.Compare.Orphans ()
17+import Data.OpenApi.Compare.Subtree
1518import Data.Proxy
1619import Data.Set (Set)
1720import qualified Data.Set as S
1821import Data.Text (Text)
19−import OpenAPI.Checker.Behavior
20−import OpenAPI.Checker.Orphans ()
21−import OpenAPI.Checker.Subtree
2222import Text.Pandoc.Builder
2323
2424instance Subtree OAuth2Flows where
@@ -26,23 +26,23 @@ instance Subtree OAuth2Flows where
2626 type SubtreeLevel OAuth2Flows = 'SecuritySchemeLevel
2727 checkStructuralCompatibility _ = structuralEq
2828 checkSemanticCompatibility env bhv pc = do
29− let supportFlow
30− :: (Subtree t, SubtreeLevel t ~ SubtreeLevel OAuth2Flows, CheckEnv OAuth2Flows ~ CheckEnv t)
31− => Issue 'SecuritySchemeLevel
32− -> ProdCons (Maybe (Traced t))
33− -> SemanticCompatFormula ()
29+ let supportFlow ::
30+ (Subtree t, SubtreeLevel t ~ SubtreeLevel OAuth2Flows, CheckEnv OAuth2Flows ~ CheckEnv t) =>
31+ Issue 'SecuritySchemeLevel ->
32+ ProdCons (Maybe (Traced t)) ->
33+ SemanticCompatFormula ()
3434 supportFlow i x = case x of
3535 -- producer will not attempt this flow
3636 (ProdCons Nothing _) -> pure ()
3737 -- producer can attempt a flow the consumer does not know about
3838 (ProdCons (Just _) Nothing) -> issueAt bhv i
3939 (ProdCons (Just p) (Just c)) ->
40− checkCompatibility env bhv $ ProdCons p c
41− getFlow
42− :: Typeable x
43− => (OAuth2Flows -> Maybe (OAuth2Flow x))
44− -> Traced OAuth2Flows
45− -> Maybe (Traced (OAuth2Flow x))
40+ checkCompatibility bhv env $ ProdCons p c
41+ getFlow ::
42+ Typeable x =>
43+ (OAuth2Flows -> Maybe (OAuth2Flow x)) ->
44+ Traced OAuth2Flows ->
45+ Maybe (Traced (OAuth2Flow x))
4646 getFlow f (Traced t a) = Traced (t >>> step (OAuth2FlowsFlow Proxy)) <$> f a
4747 supportFlow ConsumerDoesNotSupportImplicitFlow $ getFlow _oAuth2FlowsImplicit <$> pc
4848 supportFlow ConsumerDoesNotSupportPasswordFlow $ getFlow _oAuth2FlowsPassword <$> pc
@@ -52,7 +52,7 @@ instance Subtree OAuth2Flows where
5252
5353instance Typeable t => Steppable OAuth2Flows (OAuth2Flow t) where
5454 data Step OAuth2Flows (OAuth2Flow t) = OAuth2FlowsFlow (Proxy t)
55− deriving (Eq, Ord, Show)
55+ deriving stock (Eq, Ord, Show)
5656
5757instance (Typeable t, Subtree t, SubtreeLevel (OAuth2Flow t) ~ SubtreeLevel t) => Subtree (OAuth2Flow t) where
5858 type CheckEnv (OAuth2Flow t) = CheckEnv t
@@ -62,13 +62,13 @@ instance (Typeable t, Subtree t, SubtreeLevel (OAuth2Flow t) ~ SubtreeLevel t) =
6262 let ProdCons pScopes cScopes = S.fromList . IOHM.keys . _oAuth2Scopes . extract <$> prodCons
6363 missingScopes = cScopes S.\\ pScopes
6464 unless (S.null missingScopes) (issueAt bhv $ ScopesMissing missingScopes)
65− checkCompatibility env bhv $ retraced (>>> step (OAuth2FlowParamsStep Proxy)) . fmap _oAuth2Params <$> prodCons
65+ checkCompatibility bhv env $ retraced (>>> step (OAuth2FlowParamsStep Proxy)) . fmap _oAuth2Params <$> prodCons
6666 unless (((==) `on` _oAath2RefreshUrl . extract) p c) $ issueAt bhv RefreshUrlsDontMatch
6767 pure ()
6868
6969instance Typeable t => Steppable (OAuth2Flow t) t where
7070 data Step (OAuth2Flow t) t = OAuth2FlowParamsStep (Proxy t)
71− deriving (Eq, Ord, Show)
71+ deriving stock (Eq, Ord, Show)
7272
7373instance Subtree OAuth2ImplicitFlow where
7474 type SubtreeLevel OAuth2ImplicitFlow = 'SecuritySchemeLevel
@@ -103,9 +103,12 @@ instance Issuable 'SecurityRequirementLevel where
103103 = SecurityRequirementNotMet
104104 | UndefinedSecurityScheme Text
105105 deriving stock (Eq, Ord, Show)
106− issueIsUnsupported _ = False
107− describeIssue SecurityRequirementNotMet = para "Security scheme was not met."
108− describeIssue (UndefinedSecurityScheme k) = para $ "Security scheme " <> code k <> " is not defined."
106+ issueKind = \case
107+ SecurityRequirementNotMet -> CertainIssue
108+ UndefinedSecurityScheme _ -> SchemaInvalid
109+ describeIssue Forward SecurityRequirementNotMet = para "Security scheme has been removed."
110+ describeIssue Backward SecurityRequirementNotMet = para "Security scheme was added."
111+ describeIssue _ (UndefinedSecurityScheme k) = para $ "Security scheme " <> code k <> " is not defined."
109112
110113instance Issuable 'SecuritySchemeLevel where
111114 data Issue 'SecuritySchemeLevel
@@ -128,30 +131,40 @@ instance Issuable 'SecuritySchemeLevel where
128131 | CanNotHaveScopes
129132 | ScopeNotDefined Text
130133 deriving stock (Eq, Ord, Show)
131− issueIsUnsupported _ = False
132− describeIssue RefreshUrlsDontMatch = para "Refresh URLs differ."
133− describeIssue (HttpSchemeTypesDontMatch _ _) = para "HTTP scheme types don't match."
134− describeIssue (ApiKeyParamsDontMatch _ _) = para "API Key parameters don't match."
135− describeIssue (OpenIdConnectUrlsDontMatch _ _) = para "OpenaId Connect URLs don't match."
136− describeIssue (CustomHttpSchemesDontMatch e a) =
137− para $ "Expected HTTP scheme " <> code e <> " but got " <> code a <> "."
138− describeIssue ConsumerDoesNotSupportImplicitFlow = para "Implicit flow not supported."
139− describeIssue ConsumerDoesNotSupportPasswordFlow = para "Password flow not supported."
140− describeIssue ConsumerDoesNotSupportClientCridentialsFlow = para "Client Cridentials flow not supported."
141− describeIssue ConsumerDoesNotSupportAuthorizationCodeFlow = para "Authorization Code flow not supported."
142− describeIssue SecuritySchemeNotMatched = para "Security scheme not met."
143− describeIssue OAuth2ImplicitFlowNotEqual = para "Implicit Flows don't match."
144− describeIssue OAuth2PasswordFlowNotEqual = para "Password Flows don't match."
145− describeIssue OAuth2ClientCredentialsFlowNotEqual = para "Client Cridentials Flows don't match."
146− describeIssue OAuth2AuthorizationCodeFlowNotEqual = para "Authorization Code Flows don't match."
147− describeIssue (ScopesMissing ss) =
148− para "Scopes missing:" <> bulletList (S.toList ss <&> codeBlock)
149− describeIssue DifferentSecuritySchemes = para "Completely different security scheme types."
150− describeIssue CanNotHaveScopes = para "The specified security scheme can not have scopes."
151− describeIssue (ScopeNotDefined k) = para $ "Scope with key " <> code k <> " is not defined."
134+ issueKind = \case
135+ CanNotHaveScopes -> SchemaInvalid
136+ ScopeNotDefined _ -> SchemaInvalid
137+ _ -> CertainIssue
138+ describeIssue _ RefreshUrlsDontMatch = para "Refresh URL changed."
139+ describeIssue _ (HttpSchemeTypesDontMatch _ _) = para "HTTP scheme type changed."
140+ describeIssue _ (ApiKeyParamsDontMatch _ _) = para "API Key parameters changed."
141+ describeIssue _ (OpenIdConnectUrlsDontMatch _ _) = para "OpenID Connect URL changed."
142+ describeIssue _ (CustomHttpSchemesDontMatch e a) =
143+ para $ "Changed HTTP scheme from " <> code e <> " to " <> code a <> "."
144+ describeIssue Forward ConsumerDoesNotSupportImplicitFlow = para "Implicit flow support has been removed."
145+ describeIssue Backward ConsumerDoesNotSupportImplicitFlow = para "Implicit flow support has been added."
146+ describeIssue Forward ConsumerDoesNotSupportPasswordFlow = para "Password flow support has been removed."
147+ describeIssue Backward ConsumerDoesNotSupportPasswordFlow = para "Password flow support has been added."
148+ describeIssue Forward ConsumerDoesNotSupportClientCridentialsFlow = para "Client Cridentials flow support has been removed."
149+ describeIssue Backward ConsumerDoesNotSupportClientCridentialsFlow = para "Client Cridentials flow support has been added."
150+ describeIssue Forward ConsumerDoesNotSupportAuthorizationCodeFlow = para "Authorization Code flow support has been removed."
151+ describeIssue Backward ConsumerDoesNotSupportAuthorizationCodeFlow = para "Authorization Code flow support has been added."
152+ describeIssue Forward SecuritySchemeNotMatched = para "Security scheme has been removed."
153+ describeIssue Backward SecuritySchemeNotMatched = para "Security scheme has been added."
154+ describeIssue _ OAuth2ImplicitFlowNotEqual = para "Implicit Flow changed."
155+ describeIssue _ OAuth2PasswordFlowNotEqual = para "Password Flow changed."
156+ describeIssue _ OAuth2ClientCredentialsFlowNotEqual = para "Client Cridentials Flow changed."
157+ describeIssue _ OAuth2AuthorizationCodeFlowNotEqual = para "Authorization Code Flow changed."
158+ describeIssue Forward (ScopesMissing ss) =
159+ para "New scopes required:" <> bulletList (S.toList ss <&> codeBlock)
160+ describeIssue Backward (ScopesMissing ss) =
161+ para "Scopes no longer required:" <> bulletList (S.toList ss <&> codeBlock)
162+ describeIssue _ DifferentSecuritySchemes = para "Completely different security scheme types."
163+ describeIssue _ CanNotHaveScopes = para "The specified security scheme can not have scopes."
164+ describeIssue _ (ScopeNotDefined k) = para $ "Scope with key " <> code k <> " is not defined."
152165
153166instance Behavable 'SecurityRequirementLevel 'SecuritySchemeLevel where
154167 data Behave 'SecurityRequirementLevel 'SecuritySchemeLevel
155168 = SecuritySchemeStep Text
156169 deriving stock (Eq, Ord, Show)
157− describeBehaviour (SecuritySchemeStep s) = text s
170+ describeBehavior (SecuritySchemeStep s) = text s
src/OpenAPI/Checker/Validate/OpenApi.hs → src/Data/OpenApi/Compare/Validate/OpenApi.hsrenamed+29−26
@@ -2,18 +2,19 @@
22-- Does not compiles otherwise
33{-# OPTIONS_GHC -fconstraint-solver-iterations=0 #-}
44
5−module OpenAPI.Checker.Validate.OpenApi
6− ( Behave (..)
5+module Data.OpenApi.Compare.Validate.OpenApi
6+ ( Behave (..),
7+ Issue (..),
78 )
89where
910
1011import Data.HList
1112import qualified Data.HashMap.Strict.InsOrd as IOHM
1213import Data.OpenApi
13−import OpenAPI.Checker.Behavior
14−import OpenAPI.Checker.Paths
15−import OpenAPI.Checker.Subtree
16−import OpenAPI.Checker.Validate.Operation
14+import Data.OpenApi.Compare.Behavior
15+import Data.OpenApi.Compare.Paths
16+import Data.OpenApi.Compare.Subtree
17+import Data.OpenApi.Compare.Validate.Operation
1718
1819tracedPaths :: Traced OpenApi -> Traced ProcessedPathItems
1920tracedPaths oa =
@@ -37,7 +38,8 @@ tracedSecuritySchemes :: Traced OpenApi -> Traced (Definitions SecurityScheme)
3738tracedSecuritySchemes oa =
3839 traced
3940 (ask oa >>> step ComponentsSecurityScheme)
40− (_componentsSecuritySchemes . _openApiComponents . extract $ oa)
41+ (unSecurityDefinitions . _componentsSecuritySchemes . _openApiComponents . extract $ oa)
42+ where unSecurityDefinitions (SecurityDefinitions ds) = ds
4143
4244tracedResponses :: Traced OpenApi -> Traced (Definitions Response)
4345tracedResponses oa =
@@ -77,51 +79,52 @@ instance Subtree OpenApi where
7779 checkStructuralCompatibility _ _ = structuralIssue
7880 checkSemanticCompatibility _ beh prodCons = do
7981 checkCompatibility @ProcessedPathItems
80− ((tracedRequestBodies <$> prodCons)
81− `HCons` (tracedParameters <$> prodCons)
82− `HCons` (tracedSecuritySchemes <$> prodCons)
83− `HCons` (tracedResponses <$> prodCons)
84− `HCons` (tracedHeaders <$> prodCons)
85− `HCons` (tracedSchemas <$> prodCons)
86− `HCons` (_openApiServers . extract <$> prodCons)
87− `HCons` (tracedLinks <$> prodCons)
88− `HCons` (tracedCallbacks <$> prodCons)
89− `HCons` HNil)
9082 beh
83+ ( (tracedRequestBodies <$> prodCons)
84+ `HCons` (tracedParameters <$> prodCons)
85+ `HCons` (tracedSecuritySchemes <$> prodCons)
86+ `HCons` (tracedResponses <$> prodCons)
87+ `HCons` (tracedHeaders <$> prodCons)
88+ `HCons` (tracedSchemas <$> prodCons)
89+ `HCons` (_openApiServers . extract <$> prodCons)
90+ `HCons` (tracedLinks <$> prodCons)
91+ `HCons` (tracedCallbacks <$> prodCons)
92+ `HCons` HNil
93+ )
9194 (tracedPaths <$> prodCons)
9295
9396instance Steppable OpenApi ProcessedPathItems where
9497 data Step OpenApi ProcessedPathItems = OpenApiPathsStep
95− deriving (Eq, Ord, Show)
98+ deriving stock (Eq, Ord, Show)
9699
97100instance Steppable OpenApi (Definitions RequestBody) where
98101 data Step OpenApi (Definitions RequestBody) = ComponentsRequestBody
99− deriving (Eq, Ord, Show)
102+ deriving stock (Eq, Ord, Show)
100103
101104instance Steppable OpenApi (Definitions Param) where
102105 data Step OpenApi (Definitions Param) = ComponentsParam
103− deriving (Eq, Ord, Show)
106+ deriving stock (Eq, Ord, Show)
104107
105108instance Steppable OpenApi (Definitions SecurityScheme) where
106109 data Step OpenApi (Definitions SecurityScheme) = ComponentsSecurityScheme
107− deriving (Eq, Ord, Show)
110+ deriving stock (Eq, Ord, Show)
108111
109112instance Steppable OpenApi (Definitions Response) where
110113 data Step OpenApi (Definitions Response) = ComponentsResponse
111− deriving (Eq, Ord, Show)
114+ deriving stock (Eq, Ord, Show)
112115
113116instance Steppable OpenApi (Definitions Header) where
114117 data Step OpenApi (Definitions Header) = ComponentsHeader
115− deriving (Eq, Ord, Show)
118+ deriving stock (Eq, Ord, Show)
116119
117120instance Steppable OpenApi (Definitions Schema) where
118121 data Step OpenApi (Definitions Schema) = ComponentsSchema
119− deriving (Eq, Ord, Show)
122+ deriving stock (Eq, Ord, Show)
120123
121124instance Steppable OpenApi (Definitions Link) where
122125 data Step OpenApi (Definitions Link) = ComponentsLink
123− deriving (Eq, Ord, Show)
126+ deriving stock (Eq, Ord, Show)
124127
125128instance Steppable OpenApi (Definitions Callback) where
126129 data Step OpenApi (Definitions Callback) = ComponentsCallbacks
127− deriving (Eq, Ord, Show)
130+ deriving stock (Eq, Ord, Show)
src/OpenAPI/Checker/Validate/Operation.hs → src/Data/OpenApi/Compare/Validate/Operation.hsrenamed+85−97
@@ -2,18 +2,19 @@
22{-# OPTIONS_GHC -Wno-orphans #-}
33{-# OPTIONS_GHC -fconstraint-solver-iterations=0 #-}
44
5−module OpenAPI.Checker.Validate.Operation
5+module Data.OpenApi.Compare.Validate.Operation
66 ( -- * Operation
7− MatchedOperation (..)
8− , OperationMethod (..)
9− , pathItemMethod
7+ MatchedOperation (..),
8+ OperationMethod (..),
9+ pathItemMethod,
1010
1111 -- * ProcessedPathItem
12− , ProcessedPathItem (..)
13− , ProcessedPathItems (..)
14− , processPathItems
15− , Step (..)
16− , Behave (..)
12+ ProcessedPathItem (..),
13+ ProcessedPathItems (..),
14+ processPathItems,
15+ Step (..),
16+ Behave (..),
17+ Issue (..),
1718 )
1819where
1920
@@ -28,21 +29,21 @@ import qualified Data.List as L
2829import Data.Map.Strict as M
2930import Data.Maybe
3031import Data.OpenApi
32+import Data.OpenApi.Compare.Behavior
33+import Data.OpenApi.Compare.References
34+import Data.OpenApi.Compare.Subtree
35+import Data.OpenApi.Compare.Validate.MediaTypeObject
36+import Data.OpenApi.Compare.Validate.OAuth2Flows
37+import Data.OpenApi.Compare.Validate.PathFragment
38+import Data.OpenApi.Compare.Validate.Products
39+import Data.OpenApi.Compare.Validate.RequestBody
40+import Data.OpenApi.Compare.Validate.Responses
41+import Data.OpenApi.Compare.Validate.SecurityRequirement ()
42+import Data.OpenApi.Compare.Validate.Server ()
43+import Data.OpenApi.Compare.Validate.Sums
3144import Data.String
3245import Data.Text (Text)
3346import qualified Data.Text as T
34−import OpenAPI.Checker.Behavior
35−import OpenAPI.Checker.References
36−import OpenAPI.Checker.Subtree
37−import OpenAPI.Checker.Validate.MediaTypeObject
38−import OpenAPI.Checker.Validate.OAuth2Flows
39−import OpenAPI.Checker.Validate.PathFragment
40−import OpenAPI.Checker.Validate.Products
41−import OpenAPI.Checker.Validate.RequestBody
42−import OpenAPI.Checker.Validate.Responses
43−import OpenAPI.Checker.Validate.SecurityRequirement ()
44−import OpenAPI.Checker.Validate.Server ()
45−import OpenAPI.Checker.Validate.Sums
4647import Text.Pandoc.Builder
4748
4849data MatchedOperation = MatchedOperation
@@ -85,11 +86,12 @@ tracedCallbacks (Traced t oper) =
8586 | (k, v) <- IOHM.toList . _operationCallbacks . operation $ oper
8687 ]
8788
88−-- FIXME: https://github.com/typeable/openapi-diff/issues/28
89−getServers
90− :: [Server] -- ^ Servers from env
91− -> MatchedOperation
92− -> [Server]
89+-- FIXME: #28
90+getServers ::
91+ -- | Servers from env
92+ [Server] ->
93+ MatchedOperation ->
94+ [Server]
9395getServers env oper =
9496 case _operationServers . operation $ oper of
9597 [] -> env
@@ -100,21 +102,21 @@ instance Behavable 'OperationLevel 'PathFragmentLevel where
100102 = InParam Text
101103 | InFragment (PathFragment Text)
102104 deriving stock (Eq, Ord, Show)
103− describeBehaviour (InParam p) = "Parameter " <> text p
104− describeBehaviour (InFragment (StaticPath p)) = "Static fragment " <> code p
105− describeBehaviour (InFragment (DynamicPath p)) = "Dynamic fragment " <> code p
105+ describeBehavior (InParam p) = "Parameter " <> text p
106+ describeBehavior (InFragment (StaticPath p)) = "Static fragment " <> code p
107+ describeBehavior (InFragment (DynamicPath p)) = "Dynamic fragment " <> code p
106108
107109instance Behavable 'OperationLevel 'RequestLevel where
108110 data Behave 'OperationLevel 'RequestLevel
109111 = InRequest
110112 deriving stock (Eq, Ord, Show)
111− describeBehaviour InRequest = "Request"
113+ describeBehavior InRequest = "Request"
112114
113115instance Behavable 'OperationLevel 'SecurityRequirementLevel where
114116 data Behave 'OperationLevel 'SecurityRequirementLevel
115117 = SecurityRequirementStep Int
116118 deriving stock (Eq, Ord, Show)
117− describeBehaviour (SecurityRequirementStep i) =
119+ describeBehavior (SecurityRequirementStep i) =
118120 "Security requirement " <> (text . T.pack . show $ i)
119121
120122instance Subtree MatchedOperation where
@@ -202,8 +204,8 @@ instance Subtree MatchedOperation where
202204 , required = fromMaybe False . _paramRequired . extract $ p
203205 }
204206 pure (k, v)
205− check (_, name) param = do
206− checkCompatibility @Param (singletonH schemaDefs) (beh >>> step (InParam name)) param
207+ check (_, name) param =
208+ checkCompatibility @Param (beh >>> step (InParam name)) env param
207209 checkProducts beh (ParamNotMatched . snd) check elements
208210 checkPathParams :: ProdCons [Traced Param] -> SemanticCompatFormula ()
209211 checkPathParams pathParams = do
@@ -212,7 +214,7 @@ instance Subtree MatchedOperation where
212214 getFragments params mop = getPathFragments (extract mop) params
213215 -- Feed path parameters to the fragments getter
214216 check _ frags@(ProdCons (Traced _ p) _) =
215− checkCompatibility @PathFragmentParam env (beh >>> step (InFragment $ _paramName . extract <$> p)) frags
217+ checkCompatibility @PathFragmentParam (beh >>> step (InFragment $ _paramName . extract <$> p)) env frags
216218 elements =
217219 fragments <&> \frags -> M.fromList $
218220 zip [0 :: Int ..] $ do
@@ -224,7 +226,7 @@ instance Subtree MatchedOperation where
224226 }
225227 checkProducts beh PathFragmentNotMatched check elements
226228 checkRequestBodies = do
227− let check reqBody = checkCompatibility @RequestBody env (beh >>> step InRequest) reqBody
229+ let check reqBody = checkCompatibility @RequestBody (beh >>> step InRequest) env reqBody
228230 elements = getReqBody <$> bodyDefs <*> prodCons
229231 getReqBody bodyDef mop = M.fromList $ do
230232 bodyRef <- F.toList . tracedRequestBody $ mop
@@ -238,55 +240,32 @@ instance Subtree MatchedOperation where
238240 }
239241 )
240242 checkProducts beh (const NoRequestBody) (const check) elements
241− checkResponses = do
242− let respEnv =
243− HCons (swapProdCons respDefs) $
244− HCons (swapProdCons headerDefs) $
245− HCons (swapProdCons schemaDefs) $
246− HCons (swapProdCons linkDefs) HNil
247− resps = tracedResponses <$> prodCons
248− checkCompatibility respEnv beh $ swapProdCons resps
249− -- FIXME: https://github.com/typeable/openapi-diff/issues/27
243+ checkResponses =
244+ swapProdCons (checkCompatibility beh) env $ tracedResponses <$> prodCons
245+ -- FIXME: #27
250246 checkCallbacks = do
251− let env' =
252− HCons (swapProdCons respDefs) $
253− HCons (swapProdCons headerDefs) $
254− HCons (swapProdCons schemaDefs) $
255− HCons (swapProdCons securitySchemeDefs) $
256− HCons (swapProdCons paramDefs) $
257− HCons (swapProdCons serversDefs) $
258− HCons (swapProdCons callbackDefs) $
259− HCons (swapProdCons bodyDefs) $
260− HCons (swapProdCons linkDefs) HNil
261− let ProdCons pCallbacks cCallbacks = swapProdCons $ tracedCallbacks <$> prodCons
247+ let ProdCons pCallbacks cCallbacks = tracedCallbacks <$> prodCons
262248 for_ pCallbacks $ \(k, pCallback) -> do
263249 let beh' = beh >>> step (OperationCallback k)
264250 anyOfAt beh' CallbacksUnsupported $
265251 cCallbacks <&> \(_, cCallback) -> do
266− checkCompatibility env' beh' $ ProdCons pCallback cCallback
252+ swapProdCons (checkCompatibility beh') env $ ProdCons pCallback cCallback
267253 pure ()
268− -- FIXME: https://github.com/typeable/openapi-diff/issues/28
254+ -- FIXME: #28
269255 checkOperationSecurity = do
270256 let ProdCons pSecs cSecs = tracedSecurity <$> prodCons
271257 for_ pSecs $ \(i, pSec) -> do
272258 let beh' = beh >>> step (SecurityRequirementStep i)
273259 anyOfAt beh' SecurityRequirementNotMet $
274260 cSecs <&> \(_, cSec) ->
275− checkCompatibility env beh' $ ProdCons pSec cSec
261+ checkCompatibility beh' env $ ProdCons pSec cSec
276262 checkServers =
277− checkCompatibility env beh $ do
263+ checkCompatibility beh env $ do
278264 x <- prodCons
279265 se <- getH @(ProdCons [Server]) env
280266 pure $ Traced (ask x >>> step OperationServersStep) (getServers se (extract x))
281267 bodyDefs = getH @(ProdCons (Traced (Definitions RequestBody))) env
282− respDefs = getH @(ProdCons (Traced (Definitions Response))) env
283− headerDefs = getH @(ProdCons (Traced (Definitions Header))) env
284− schemaDefs = getH @(ProdCons (Traced (Definitions Schema))) env
285268 paramDefs = getH @(ProdCons (Traced (Definitions Param))) env
286− linkDefs = getH @(ProdCons (Traced (Definitions Link))) env
287− callbackDefs = getH @(ProdCons (Traced (Definitions Callback))) env
288− securitySchemeDefs = getH @(ProdCons (Traced (Definitions SecurityScheme))) env
289− serversDefs = getH @(ProdCons [Server]) env
290269
291270data OperationMethod
292271 = GetMethod
@@ -297,7 +276,7 @@ data OperationMethod
297276 | HeadMethod
298277 | PatchMethod
299278 | TraceMethod
300− deriving (Eq, Ord, Show)
279+ deriving stock (Eq, Ord, Show)
301280
302281pathItemMethod :: OperationMethod -> PathItem -> Maybe Operation
303282pathItemMethod = \case
@@ -334,7 +313,7 @@ instance Steppable MatchedOperation [Server] where
334313 data Step MatchedOperation [Server]
335314 = OperationServersStep
336315 | EnvServerStep
337− deriving (Eq, Ord, Show)
316+ deriving stock (Eq, Ord, Show)
338317
339318-- * ProcessedPathItems
340319
@@ -357,16 +336,23 @@ instance Issuable 'APILevel where
357336 | AllPathsFailed FilePath
358337 -- When several paths match given but all checks failed
359338 deriving stock (Eq, Ord, Show)
360− issueIsUnsupported _ = False
361− describeIssue (NoPathsMatched p) = para $ "The path " <> (code . T.pack) p <> " did not match anything."
362− describeIssue (AllPathsFailed p) = para $ "The path " <> (code . T.pack) p <> " did not match anything."
339+ issueKind = \case
340+ _ -> CertainIssue
341+ relatedIssues =
342+ (==) `withClass` \case
343+ NoPathsMatched fp -> Just fp
344+ AllPathsFailed fp -> Just fp
345+ 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."
347+ describeIssue Forward (AllPathsFailed p) = para $ "The path " <> (code . T.pack) p <> " has been removed."
348+ describeIssue Backward (AllPathsFailed p) = para $ "The path " <> (code . T.pack) p <> " has been added."
363349
364350instance Behavable 'APILevel 'PathLevel where
365351 data Behave 'APILevel 'PathLevel
366352 = AtPath FilePath
367353 deriving stock (Eq, Ord, Show)
368354
369− describeBehaviour (AtPath p) = str (T.pack p)
355+ describeBehavior (AtPath p) = str (T.pack p)
370356
371357instance Subtree ProcessedPathItems where
372358 type SubtreeLevel ProcessedPathItems = 'APILevel
@@ -396,10 +382,10 @@ instance Subtree ProcessedPathItems where
396382 F.toList $ matchingPathItems $ ProdCons prodItem consItem
397383 case matchedItems of
398384 [] -> issueAt beh $ NoPathsMatched prodPath
399− [match] -> checkCompatibility env beh' (retraced <$> pc <*> match)
385+ [match] -> checkCompatibility beh' env (retraced <$> pc <*> match)
400386 matches -> anyOfAt beh (AllPathsFailed prodPath) $ do
401387 match <- matches
402− pure $ checkCompatibility env beh' (retraced <$> pc <*> match)
388+ pure $ checkCompatibility beh' env (retraced <$> pc <*> match)
403389 where
404390 retraced pc mpi = traced (ask pc >>> step (MatchedPathStep $ matchedPath mpi)) mpi
405391
@@ -450,25 +436,27 @@ tracedFragments mpi =
450436 | (i, x) <- L.zip [0 ..] $ pathFragments $ extract mpi
451437 ]
452438
453−tracedMethod
454− :: OperationMethod
455− -> Traced MatchedPathItem
456− -> Maybe (Traced' MatchedOperation Operation)
439+tracedMethod ::
440+ OperationMethod ->
441+ Traced MatchedPathItem ->
442+ Maybe (Traced' MatchedOperation Operation)
457443tracedMethod s mpi = env (ask mpi >>> step (OperationMethodStep s)) <$> (pathItemMethod s . pathItem . extract $ mpi)
458444
459445instance Issuable 'PathLevel where
460446 data Issue 'PathLevel
461447 = OperationMissing OperationMethod
462448 deriving stock (Eq, Ord, Show)
463− issueIsUnsupported _ = False
464− describeIssue (OperationMissing op) = para $ "Method " <> strong (showMethod op) <> " is not defined."
449+ issueKind = \case
450+ OperationMissing _ -> CertainIssue
451+ describeIssue Forward (OperationMissing op) = para $ "Method " <> strong (showMethod op) <> " has been removed."
452+ describeIssue Backward (OperationMissing op) = para $ "Method " <> strong (showMethod op) <> " has been added."
465453
466454instance Behavable 'PathLevel 'OperationLevel where
467455 data Behave 'PathLevel 'OperationLevel
468456 = InOperation OperationMethod
469− deriving (Eq, Ord, Show)
457+ deriving stock (Eq, Ord, Show)
470458
471− describeBehaviour (InOperation method) = showMethod method
459+ describeBehavior (InOperation method) = showMethod method
472460
473461showMethod :: IsString s => OperationMethod -> s
474462showMethod = \case
@@ -499,10 +487,10 @@ instance Subtree MatchedPathItem where
499487 checkSemanticCompatibility env beh prodCons = do
500488 let paramDefs = getH @(ProdCons (Traced (Definitions Param))) env
501489 pathTracedParams = getPathParams <$> paramDefs <*> prodCons
502− getPathParams
503− :: Traced (Definitions Param)
504− -> Traced MatchedPathItem
505− -> [Traced Param]
490+ getPathParams ::
491+ Traced (Definitions Param) ->
492+ Traced MatchedPathItem ->
493+ [Traced Param]
506494 getPathParams defs mpi = do
507495 paramRef <- tracedMatchedPathItemParameters mpi
508496 pure $ dereference defs paramRef
@@ -531,26 +519,26 @@ instance Subtree MatchedPathItem where
531519 -- Got only Justs here
532520 let retraced = \op -> MatchedOperation {operation = op, pathParams, getPathFragments}
533521 pure (name, retraced <$> operation)
534− check name pc = checkCompatibility @MatchedOperation env (beh >>> step (InOperation name)) pc
522+ check name pc = checkCompatibility @MatchedOperation (beh >>> step (InOperation name)) env pc
535523 -- Operations are sum-like entities. Use step to operation as key because
536524 -- why not
537525 checkSums beh OperationMissing check operations
538526
539527instance Steppable ProcessedPathItems MatchedPathItem where
540528 data Step ProcessedPathItems MatchedPathItem = MatchedPathStep FilePath
541− deriving (Eq, Ord, Show)
529+ deriving stock (Eq, Ord, Show)
542530
543531instance Steppable MatchedPathItem MatchedOperation where
544532 data Step MatchedPathItem MatchedOperation = OperationMethodStep OperationMethod
545− deriving (Eq, Ord, Show)
533+ deriving stock (Eq, Ord, Show)
546534
547535instance Steppable MatchedPathItem (Referenced Param) where
548536 data Step MatchedPathItem (Referenced Param) = PathItemParam Int
549− deriving (Eq, Ord, Show)
537+ deriving stock (Eq, Ord, Show)
550538
551539instance Steppable MatchedPathItem PathFragmentParam where
552540 data Step MatchedPathItem PathFragmentParam = PathFragmentStep Int
553− deriving (Eq, Ord, Show)
541+ deriving stock (Eq, Ord, Show)
554542
555543-- * Callbacks
556544
@@ -575,10 +563,10 @@ instance Subtree Callback where
575563instance Issuable 'CallbackLevel where
576564 data Issue 'CallbackLevel
577565 = CallbacksUnsupported
578− deriving (Eq, Ord, Show)
579− issueIsUnsupported = \case
580− CallbacksUnsupported -> True
581− describeIssue CallbacksUnsupported = para "OpenApi Diff does not currently support callbacks."
566+ deriving stock (Eq, Ord, Show)
567+ issueKind = \case
568+ CallbacksUnsupported -> Unsupported
569+ describeIssue _ CallbacksUnsupported = para "CompaREST does not currently support callbacks."
582570
583571tracedCallbackPathItems :: Traced Callback -> Traced ProcessedPathItems
584572tracedCallbackPathItems (Traced t (Callback x)) =
@@ -586,10 +574,10 @@ tracedCallbackPathItems (Traced t (Callback x)) =
586574
587575instance Steppable Callback ProcessedPathItems where
588576 data Step Callback ProcessedPathItems = CallbackPathsStep
589− deriving (Eq, Ord, Show)
577+ deriving stock (Eq, Ord, Show)
590578
591579instance Behavable 'OperationLevel 'CallbackLevel where
592580 data Behave 'OperationLevel 'CallbackLevel = OperationCallback Text
593581 deriving stock (Eq, Ord, Show)
594582
595− describeBehaviour (OperationCallback key) = "Operation " <> code key
583+ describeBehavior (OperationCallback key) = "Operation " <> code key
src/OpenAPI/Checker/Validate/Param.hs → src/Data/OpenApi/Compare/Validate/Param.hsrenamed+63−48
@@ -1,20 +1,21 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
33
4−module OpenAPI.Checker.Validate.Param
5− ( Behave (..)
6− , Issue (..)
7− ) where
4+module Data.OpenApi.Compare.Validate.Param
5+ ( Behave (..),
6+ Issue (..),
7+ )
8+where
89
9−import Control.Lens hiding (para)
1010import Control.Monad
11+import Data.Functor
1112import Data.Maybe
1213import Data.OpenApi
14+import Data.OpenApi.Compare.Behavior
15+import Data.OpenApi.Compare.Orphans ()
16+import Data.OpenApi.Compare.Subtree
17+import Data.OpenApi.Compare.Validate.Schema ()
1318import Data.Text as T
14−import OpenAPI.Checker.Behavior
15−import OpenAPI.Checker.Orphans ()
16−import OpenAPI.Checker.Subtree
17−import OpenAPI.Checker.Validate.Schema ()
1819import Text.Pandoc.Builder
1920
2021-- | The type is normalized encoding style of the parameter. If two encoding
@@ -22,13 +23,18 @@ import Text.Pandoc.Builder
2223data EncodingStyle = EncodingStyle
2324 { style :: Style
2425 , explode :: Bool
25− , allowReserved :: Maybe Bool
26− -- ^ Nothing when @in@ parameter is not @query@
27− } deriving (Eq, Ord, Show)
26+ , -- | Nothing when @in@ parameter is not @query@
27+ allowReserved :: Maybe Bool
28+ }
29+ deriving stock (Eq, Ord, Show)
2830
2931paramEncoding :: Param -> EncodingStyle
30−paramEncoding p = EncodingStyle
31− { style, explode, allowReserved }
32+paramEncoding p =
33+ EncodingStyle
34+ { style
35+ , explode
36+ , allowReserved
37+ }
3238 where
3339 style = fromMaybe defaultStyle $ _paramStyle p
3440 defaultStyle = case _paramIn p of
@@ -49,34 +55,39 @@ tracedSchema par = _paramSchema (extract par) <&> traced (ask par >>> step Param
4955
5056instance Issuable 'PathFragmentLevel where
5157 data Issue 'PathFragmentLevel
52− = ParamNameMismatch
53− -- ^ Params have different names
54− | ParamEmptinessIncompatible
55− -- ^ Consumer requires non-empty param, but producer gives emptyable
56− | ParamRequired
57− -- ^ Consumer requires mandatory parm, but producer optional
58+ = -- | Params have different names
59+ ParamNameMismatch
60+ | -- | Consumer requires non-empty param, but producer gives emptyable
61+ ParamEmptinessIncompatible
62+ | -- | Consumer requires mandatory parm, but producer optional
63+ ParamRequired
5864 | ParamPlaceIncompatible
59− | ParamStyleMismatch
60− -- ^ Params encoded in different styles
61− | ParamSchemaMismatch
62− -- ^ One of schemas not presented
63− | PathFragmentsDontMatch Text Text
64− deriving (Eq, Ord, Show)
65− issueIsUnsupported _ = False
66− describeIssue ParamNameMismatch = para "The path fragments don't match."
67− describeIssue ParamEmptinessIncompatible = para "Expected that an empty parameter is allowed, but it isn't."
68− describeIssue ParamRequired = para "Expected the parameter to be optional, but it is required."
69− describeIssue ParamPlaceIncompatible = para "Parameters in incompatible locations."
70− describeIssue ParamStyleMismatch = para "Different parameter styles (encodings)."
71− describeIssue ParamSchemaMismatch = para "Expected a schema, but didn't find one."
72− describeIssue (PathFragmentsDontMatch e a) = para $ "Expected " <> code e <> " but got " <> code a <> "."
65+ | -- | Params encoded in different styles
66+ ParamStyleMismatch
67+ | -- | One of schemas not presented
68+ ParamSchemaMismatch
69+ | PathFragmentsDontMatch (ProdCons Text)
70+ deriving stock (Eq, Ord, Show)
71+ issueKind = \case
72+ ParamSchemaMismatch -> ProbablyIssue -- the schema could be catch-all (?)
73+ _ -> CertainIssue
74+ describeIssue _ ParamNameMismatch = para "The path fragments don't match."
75+ describeIssue Forward ParamEmptinessIncompatible = para "The parameter can no longer be empty."
76+ describeIssue Backward ParamEmptinessIncompatible = para "The parameter can now be empty."
77+ describeIssue Forward ParamRequired = para "Parameter has become required."
78+ describeIssue Backward ParamRequired = para "Parameter is no longer required."
79+ describeIssue _ ParamPlaceIncompatible = para "Parameters in incompatible locations."
80+ describeIssue _ ParamStyleMismatch = para "Different parameter styles (encodings)."
81+ describeIssue _ ParamSchemaMismatch = para "Expected a schema, but didn't find one."
82+ describeIssue ori (PathFragmentsDontMatch (orientProdCons ori -> ProdCons e a)) =
83+ para $ "Parameter changed from " <> code e <> " to " <> code a <> "."
7384
7485instance Behavable 'PathFragmentLevel 'SchemaLevel where
7586 data Behave 'PathFragmentLevel 'SchemaLevel
7687 = InParamSchema
77− deriving (Eq, Ord, Show)
78−
79− describeBehaviour InParamSchema = "JSON Schema"
88+ deriving stock (Eq, Ord, Show)
89+
90+ describeBehavior InParamSchema = "JSON Schema"
8091
8192instance Subtree Param where
8293 type SubtreeLevel Param = 'PathFragmentLevel
@@ -92,30 +103,34 @@ instance Subtree Param where
92103 structuralEq $ fmap _paramExplode <$> pc
93104 pure ()
94105 checkSemanticCompatibility env beh pc@(ProdCons p c) = do
95− when (_paramName (extract p) /= _paramName (extract c))
96− $ issueAt beh ParamNameMismatch
97− when ((fromMaybe False . _paramRequired . extract $ c) &&
98− not (fromMaybe False . _paramRequired . extract $ p))
106+ when (_paramName (extract p) /= _paramName (extract c)) $
107+ issueAt beh ParamNameMismatch
108+ when
109+ ( (fromMaybe False . _paramRequired . extract $ c)
110+ && not (fromMaybe False . _paramRequired . extract $ p)
111+ )
99112 $ issueAt beh ParamRequired
100113 case (_paramIn . extract $ p, _paramIn . extract $ c) of
101114 (ParamQuery, ParamQuery) -> do
102115 -- Emptiness is only for query params
103− when ((fromMaybe False . _paramAllowEmptyValue . extract $ p)
104− && not (fromMaybe False . _paramAllowEmptyValue . extract $ c))
116+ when
117+ ( (fromMaybe False . _paramAllowEmptyValue . extract $ p)
118+ && not (fromMaybe False . _paramAllowEmptyValue . extract $ c)
119+ )
105120 $ issueAt beh ParamEmptinessIncompatible
106121 (a, b) | a == b -> pure ()
107122 _ -> issueAt beh ParamPlaceIncompatible
108− unless (paramEncoding (extract p) == paramEncoding (extract c))
109− $ issueAt beh ParamStyleMismatch
123+ unless (paramEncoding (extract p) == paramEncoding (extract c)) $
124+ issueAt beh ParamStyleMismatch
110125 case tracedSchema <$> pc of
111126 ProdCons (Just prodSchema) (Just consSchema) -> do
112− checkCompatibility env (beh >>> step InParamSchema) $ ProdCons prodSchema consSchema
127+ checkCompatibility (beh >>> step InParamSchema) env $ ProdCons prodSchema consSchema
113128 ProdCons Nothing Nothing -> pure ()
114129 ProdCons Nothing (Just _consSchema) -> issueAt beh ParamSchemaMismatch
115130 ProdCons (Just _prodSchema) Nothing -> pure ()
116− -- If consumer doesn't care then why we should?
131+ -- If consumer doesn't care then why we should?
117132 pure ()
118133
119134instance Steppable Param (Referenced Schema) where
120135 data Step Param (Referenced Schema) = ParamSchema
121− deriving (Eq, Ord, Show)
136+ deriving stock (Eq, Ord, Show)
src/OpenAPI/Checker/Validate/PathFragment.hs → src/Data/OpenApi/Compare/Validate/PathFragment.hsrenamed+28−24
@@ -1,21 +1,20 @@
1−module OpenAPI.Checker.Validate.PathFragment
2− ( parsePath
3− , PathFragment (..)
4− , PathFragmentParam
1+module Data.OpenApi.Compare.Validate.PathFragment
2+ ( parsePath,
3+ PathFragment (..),
4+ PathFragmentParam,
55 )
66where
77
88import qualified Data.Aeson as A
99import Data.OpenApi
10+import Data.OpenApi.Compare.Behavior
11+import Data.OpenApi.Compare.Subtree
12+import Data.OpenApi.Compare.Validate.Param
1013import Data.Text (Text)
1114import qualified Data.Text as T
12−import Data.Typeable
13−import OpenAPI.Checker.Behavior
14−import OpenAPI.Checker.Subtree
15−import OpenAPI.Checker.Validate.Param
1615
1716-- TODO: templates can be only part of the PathFragment. Currently only supports templates as full PathFragment.
18−-- https://github.com/typeable/openapi-diff/issues/23
17+-- #23
1918parsePath :: FilePath -> [PathFragment Text]
2019parsePath = fmap partition . T.splitOn "/" . T.pack
2120 where
@@ -38,17 +37,19 @@ type PathFragmentParam = PathFragment (Traced Param)
3837
3938instance (Typeable param) => Steppable (PathFragment param) Param where
4039 data Step (PathFragment param) Param = StaticPathParam Text
41− deriving (Eq, Ord, Show)
40+ deriving stock (Eq, Ord, Show)
4241
4342tracedPathFragmentParam :: Traced PathFragmentParam -> Traced Param
4443tracedPathFragmentParam pfp = case extract pfp of
45− StaticPath s -> traced (ask pfp >>> step (StaticPathParam s))
46− $ mempty
47− { _paramRequired = Just True
48− , _paramIn = ParamPath
49− , _paramAllowEmptyValue = Just False
50− , _paramAllowReserved = Just False
51− , _paramSchema = Just $ Inline $ staticStringSchema s }
44+ StaticPath s ->
45+ traced (ask pfp >>> step (StaticPathParam s)) $
46+ mempty
47+ { _paramRequired = Just True
48+ , _paramIn = ParamPath
49+ , _paramAllowEmptyValue = Just False
50+ , _paramAllowReserved = Just False
51+ , _paramSchema = Just $ Inline $ staticStringSchema s
52+ }
5253 DynamicPath p -> p
5354
5455staticStringSchema :: Text -> Schema
@@ -61,14 +62,17 @@ staticStringSchema t =
6162
6263instance Subtree PathFragmentParam where
6364 type SubtreeLevel PathFragmentParam = 'PathFragmentLevel
64− type CheckEnv PathFragmentParam =
65− '[ ProdCons (Traced (Definitions Schema)) ]
65+ type
66+ CheckEnv PathFragmentParam =
67+ '[ProdCons (Traced (Definitions Schema))]
68+
6669 -- Not much to compare at this level
67− checkStructuralCompatibility _ _ = structuralIssue
70+ checkStructuralCompatibility _ _ = structuralIssue
71+
6872 -- This case isn't strictly needed. It is here for optimization.
69− checkSemanticCompatibility _ beh (ProdCons (extract -> StaticPath x) (extract -> StaticPath y))
70− = if x == y
73+ checkSemanticCompatibility _ beh (ProdCons (extract -> StaticPath x) (extract -> StaticPath y)) =
74+ if x == y
7175 then pure ()
72− else issueAt beh (PathFragmentsDontMatch x y)
76+ else issueAt beh (PathFragmentsDontMatch (ProdCons x y))
7377 checkSemanticCompatibility env beh prodCons = do
74− checkCompatibility env beh (tracedPathFragmentParam <$> prodCons)
78+ checkCompatibility beh env (tracedPathFragmentParam <$> prodCons)
src/Data/OpenApi/Compare/Validate/Products.hsnew file+48
@@ -0,0 +1,48 @@
1+-- | Checks product-like entities. The key is some identificator for the product
2+--element. Each element may be required or optional.
3+--
4+--One example of product is request parameters. There are optional and required
5+--parameters. The client and server have possibly different set of
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.
8+--
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)
11+--and their schemas match.
12+--
13+--This module abstracts this logic for arbitrary elements
14+module Data.OpenApi.Compare.Validate.Products
15+ ( checkProducts,
16+ ProductLike (..),
17+ )
18+where
19+
20+import Data.Foldable
21+import Data.Map.Strict (Map)
22+import qualified Data.Map.Strict as M
23+import Data.OpenApi.Compare.Behavior
24+import Data.OpenApi.Compare.Paths
25+import Data.OpenApi.Compare.Subtree
26+
27+-- | Some entity which is product-like
28+data ProductLike a = ProductLike
29+ { productValue :: a
30+ , required :: Bool
31+ }
32+
33+checkProducts ::
34+ (Ord k, Issuable l) =>
35+ Paths q r l ->
36+ -- | No required element found
37+ (k -> Issue l) ->
38+ (k -> ProdCons t -> CompatFormula' q AnIssue r ()) ->
39+ ProdCons (Map k (ProductLike t)) ->
40+ CompatFormula' q AnIssue r ()
41+checkProducts xs noElt check (ProdCons p c) = for_ (M.toList c) $ \(key, consElt) ->
42+ case M.lookup key p of
43+ Nothing -> case required consElt of
44+ True -> issueAt xs $ noElt key
45+ False -> pure ()
46+ Just prodElt -> do
47+ let elts = ProdCons prodElt consElt
48+ check key (productValue <$> elts)
src/OpenAPI/Checker/Validate/RequestBody.hs → src/Data/OpenApi/Compare/Validate/RequestBody.hsrenamed+21−16
@@ -1,8 +1,8 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.Validate.RequestBody
4− ( Issue (..)
5− , Behave (..)
3+module Data.OpenApi.Compare.Validate.RequestBody
4+ ( Issue (..),
5+ Behave (..),
66 )
77where
88
@@ -11,12 +11,12 @@ import Data.HashMap.Strict.InsOrd as IOHM
1111import Data.Map.Strict as M
1212import Data.Maybe
1313import Data.OpenApi
14+import Data.OpenApi.Compare.Behavior
15+import Data.OpenApi.Compare.Subtree
16+import Data.OpenApi.Compare.Validate.MediaTypeObject
17+import Data.OpenApi.Compare.Validate.Sums
1418import qualified Data.Text as T
1519import Network.HTTP.Media (MediaType)
16−import OpenAPI.Checker.Behavior
17−import OpenAPI.Checker.Subtree
18−import OpenAPI.Checker.Validate.MediaTypeObject
19−import OpenAPI.Checker.Validate.Sums
2020import Text.Pandoc.Builder
2121
2222-- TODO: Use RequestMediaTypeObjectMapping
@@ -30,17 +30,22 @@ instance Issuable 'RequestLevel where
3030 = RequestBodyRequired
3131 | RequestMediaTypeNotFound MediaType
3232 deriving stock (Eq, Ord, Show)
33− issueIsUnsupported _ = False
34− describeIssue RequestBodyRequired =
35− para "Expected the request body to be optional, but found it to be required."
36− describeIssue (RequestMediaTypeNotFound t) =
37− para $ "Couldn't find a request body for media type " <> (code . T.pack . show $ t) <> "."
33+ issueKind = \case
34+ _ -> CertainIssue
35+ describeIssue Forward RequestBodyRequired =
36+ para "Request body has become required."
37+ describeIssue Backward RequestBodyRequired =
38+ para "Request body is no longer required."
39+ describeIssue Forward (RequestMediaTypeNotFound t) =
40+ para $ "Media type " <> (code . T.pack . show $ t) <> " has been removed."
41+ describeIssue Backward (RequestMediaTypeNotFound t) =
42+ para $ "Media type " <> (code . T.pack . show $ t) <> " has been added."
3843
3944instance Behavable 'RequestLevel 'PayloadLevel where
4045 data Behave 'RequestLevel 'PayloadLevel
4146 = InPayload
4247 deriving stock (Eq, Ord, Show)
43− describeBehaviour InPayload = "Payload"
48+ describeBehavior InPayload = "Payload"
4449
4550instance Subtree RequestBody where
4651 type SubtreeLevel RequestBody = 'RequestLevel
@@ -60,15 +65,15 @@ instance Subtree RequestBody where
6065 then issueAt beh RequestBodyRequired
6166 else -- Media type object are sums-like entities.
6267
63− let check mediaType pc = checkCompatibility @MediaTypeObject (HCons mediaType env) (beh >>> step InPayload) pc
68+ let check mediaType pc = checkCompatibility @MediaTypeObject (beh >>> step InPayload) (HCons mediaType env) pc
6469 sumElts = getSum <$> prodCons
6570 getSum rb = M.fromList . IOHM.toList $ tracedContent rb
6671 in checkSums beh RequestMediaTypeNotFound check sumElts
6772
6873instance Steppable RequestBody MediaTypeObject where
6974 data Step RequestBody MediaTypeObject = RequestMediaTypeObject MediaType
70− deriving (Eq, Ord, Show)
75+ deriving stock (Eq, Ord, Show)
7176
7277instance Steppable RequestBody (IOHM.InsOrdHashMap MediaType MediaTypeObject) where
7378 data Step RequestBody (IOHM.InsOrdHashMap MediaType MediaTypeObject) = RequestMediaTypeObjectMapping
74− deriving (Eq, Ord, Show)
79+ deriving stock (Eq, Ord, Show)
src/OpenAPI/Checker/Validate/Responses.hs → src/Data/OpenApi/Compare/Validate/Responses.hsrenamed+32−27
@@ -1,8 +1,8 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
33
4−module OpenAPI.Checker.Validate.Responses
5− ( Behave (..)
4+module Data.OpenApi.Compare.Validate.Responses
5+ ( Behave (..),
66 )
77where
88
@@ -11,17 +11,17 @@ import Data.HashMap.Strict.InsOrd as IOHM
1111import Data.Map.Strict as M
1212import Data.Maybe
1313import Data.OpenApi
14+import Data.OpenApi.Compare.Behavior
15+import Data.OpenApi.Compare.References
16+import Data.OpenApi.Compare.Subtree
17+import Data.OpenApi.Compare.Validate.Header ()
18+import Data.OpenApi.Compare.Validate.Link ()
19+import Data.OpenApi.Compare.Validate.MediaTypeObject
20+import Data.OpenApi.Compare.Validate.Products
21+import Data.OpenApi.Compare.Validate.Schema ()
22+import Data.OpenApi.Compare.Validate.Sums
1423import qualified Data.Text as T
1524import Network.HTTP.Media (MediaType)
16−import OpenAPI.Checker.Behavior
17−import OpenAPI.Checker.References
18−import OpenAPI.Checker.Subtree
19−import OpenAPI.Checker.Validate.Header ()
20−import OpenAPI.Checker.Validate.Link ()
21−import OpenAPI.Checker.Validate.MediaTypeObject
22−import OpenAPI.Checker.Validate.Products
23−import OpenAPI.Checker.Validate.Schema ()
24−import OpenAPI.Checker.Validate.Sums
2525import Text.Pandoc.Builder
2626
2727tracedResponses :: Traced Responses -> IOHM.InsOrdHashMap HttpStatusCode (Traced (Referenced Response))
@@ -49,12 +49,12 @@ instance Subtree Responses where
4949 -- one element
5050 checkSemanticCompatibility env beh prodCons = do
5151 let defs = getH @(ProdCons (Traced (Definitions Response))) env
52− check code resps = checkCompatibility @Response env (beh >>> step (WithStatusCode code)) resps
52+ check code resps = checkCompatibility @Response (beh >>> step (WithStatusCode code)) env resps
5353 elements = getEls <$> defs <*> prodCons
5454 getEls respDef resps = M.fromList $ do
5555 (code, respRef) <- IOHM.toList $ tracedResponses resps
5656 pure (code, dereference respDef respRef)
57− checkSums beh ResponseCodeNotFound check elements
57+ checkSums beh ConsumerDoesntHaveResponseCode check elements
5858
5959tracedContent :: Traced Response -> IOHM.InsOrdHashMap MediaType (Traced MediaTypeObject)
6060tracedContent resp =
@@ -68,28 +68,33 @@ tracedHeaders resp =
6868
6969instance Issuable 'ResponseLevel where
7070 data Issue 'ResponseLevel
71− = ResponseMediaTypeMissing MediaType
72− | ResponseHeaderMissing HeaderName
71+ = ConsumerDoesntHaveMediaType MediaType
72+ | ProducerDoesntHaveResponseHeader HeaderName
7373 deriving stock (Eq, Ord, Show)
74− issueIsUnsupported _ = False
75− describeIssue (ResponseMediaTypeMissing t) =
76− para $ "Couldn't find reponse for media type " <> (code . T.pack . show $ t) <> "."
77− describeIssue (ResponseHeaderMissing h) =
78− para $ "Couldn't find header " <> code h <> "."
74+ issueKind = \case
75+ _ -> CertainIssue
76+ describeIssue Forward (ConsumerDoesntHaveMediaType t) =
77+ para $ "Media type was removed: " <> (code . T.pack . show $ t) <> "."
78+ describeIssue Backward (ConsumerDoesntHaveMediaType t) =
79+ para $ "Media type was added: " <> (code . T.pack . show $ t) <> "."
80+ describeIssue Forward (ProducerDoesntHaveResponseHeader h) =
81+ para $ "New header was added " <> code h <> "."
82+ describeIssue Backward (ProducerDoesntHaveResponseHeader h) =
83+ para $ "Header was removed " <> code h <> "."
7984
8085instance Behavable 'ResponseLevel 'PayloadLevel where
8186 data Behave 'ResponseLevel 'PayloadLevel
8287 = ResponsePayload
8388 deriving stock (Eq, Ord, Show)
8489
85− describeBehaviour ResponsePayload = "Payload"
90+ describeBehavior ResponsePayload = "Payload"
8691
8792instance Behavable 'ResponseLevel 'HeaderLevel where
8893 data Behave 'ResponseLevel 'HeaderLevel
8994 = InHeader HeaderName
9095 deriving stock (Eq, Ord, Show)
9196
92− describeBehaviour (InHeader name) = "Header " <> code name
97+ describeBehavior (InHeader name) = "Header " <> code name
9398
9499instance Subtree Response where
95100 type SubtreeLevel Response = 'ResponseLevel
@@ -113,15 +118,15 @@ instance Subtree Response where
113118 checkMediaTypes = do
114119 -- Media types are sum-like entity
115120 let check mediaType mtObj =
116− let mtEnv = HCons mediaType $ env
117− in checkCompatibility @MediaTypeObject mtEnv (beh >>> step ResponsePayload) mtObj
121+ let mtEnv = HCons mediaType env
122+ in checkCompatibility @MediaTypeObject (beh >>> step ResponsePayload) mtEnv mtObj
118123 elements = getEls <$> prodCons
119124 getEls resp = M.fromList . IOHM.toList $ tracedContent resp
120− checkSums beh ResponseMediaTypeMissing check elements
125+ checkSums beh ConsumerDoesntHaveMediaType check elements
121126
122127 checkHeaders = do
123128 -- Headers are product-like entities
124− let check name hdrs = checkCompatibility @Header env (beh >>> step (InHeader name)) hdrs
129+ let check name hdrs = checkCompatibility @Header (beh >>> step (InHeader name)) env hdrs
125130 elements = getEls <$> headerDefs <*> prodCons
126131 getEls headerDef resp = M.fromList $ do
127132 (hname, headerRef) <- IOHM.toList $ tracedHeaders resp
@@ -133,7 +138,7 @@ instance Subtree Response where
133138 , required = fromMaybe False . _headerRequired . extract $ header
134139 }
135140 )
136− checkProducts beh ResponseHeaderMissing check elements
141+ checkProducts beh ProducerDoesntHaveResponseHeader check elements
137142 headerDefs = getH @(ProdCons (Traced (Definitions Header))) env
138143
139144instance Steppable Responses (Referenced Response) where
src/Data/OpenApi/Compare/Validate/Schema.hsnew file+398
@@ -0,0 +1,398 @@
1+{-# OPTIONS_GHC -Wno-orphans #-}
2+
3+module Data.OpenApi.Compare.Validate.Schema
4+ (
5+ )
6+where
7+
8+import Control.Monad (when,unless)
9+import qualified Data.Aeson as A
10+import Data.Coerce
11+import Data.Foldable (for_, toList)
12+import Data.Functor
13+import Data.HList
14+import Data.List (genericIndex, genericLength, group)
15+import qualified Data.List.NonEmpty as NE
16+import qualified Data.Map as M
17+import Data.Maybe
18+import Data.OpenApi
19+import Data.OpenApi.Compare.Behavior
20+import Data.OpenApi.Compare.Paths
21+import qualified Data.OpenApi.Compare.PathsPrefixTree as P
22+import Data.OpenApi.Compare.Subtree
23+import Data.OpenApi.Compare.Validate.Schema.DNF
24+import Data.OpenApi.Compare.Validate.Schema.Issues
25+import Data.OpenApi.Compare.Validate.Schema.JsonFormula
26+import Data.OpenApi.Compare.Validate.Schema.Partition
27+import Data.OpenApi.Compare.Validate.Schema.Process
28+import Data.OpenApi.Compare.Validate.Schema.Traced
29+import Data.OpenApi.Compare.Validate.Schema.TypedJson
30+import Data.Ord
31+import Data.Ratio
32+import Data.Semigroup
33+import qualified Data.Set as S
34+import Data.Text (Text)
35+
36+checkFormulas ::
37+ (ReassembleHList xs (CheckEnv (Referenced Schema))) =>
38+ HList xs ->
39+ Behavior 'SchemaLevel ->
40+ ProdCons (Trace Schema) ->
41+ ProdCons (Traced (Definitions Schema)) ->
42+ ProdCons (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel) ->
43+ SemanticCompatFormula ()
44+checkFormulas env beh trs defs (ProdCons (fp, ep) (fc, ec)) =
45+ case P.toList ep ++ P.toList ec of
46+ issues@(_ : _) -> for_ issues $ embedFormula beh . anItem
47+ [] -> do
48+ -- We have the following isomorphisms:
49+ -- (A ⊂ X ∩ Y) = (A ⊂ X) /\ (A ⊂ Y)
50+ -- (A ⊂ ⊤) = 1
51+ -- (X ∪ Y ⊂ B) = (X ⊂ B) /\ (Y ⊂ B)
52+ -- (∅ ⊂ B) = 1
53+ -- The remaining cases are, notably, not isomorphisms:
54+ -- 1) (A ⊂ X ∪ Y) <= (A ⊂ X) \/ (A ⊂ Y)
55+ -- 2) (A ⊂ ∅) <= 0
56+ -- 3) (X ∩ Y ⊂ B) <= (X ⊂ B) \/ (Y ⊂ B)
57+ -- 4) (⊤ ⊂ B) <= 0
58+ -- Therefore we have the implications with (∃ and ∀ being the N-ary
59+ -- versions of \/ and /\ respectively):
60+ -- (⋃_i ⋂_j A[i,j]) ⊂ (⋃_k ⋂_l B[k,l])
61+ -- <= ∃k ∀l ∀i, (⋂_j A[i,j]) ⊂ B[k,l]
62+ -- = ∀i ∃k ∀l, (⋂_j A[i,j]) ⊂ B[k,l]
63+ -- with the caveat that the the set over which k ranges is nonempty.
64+ -- (because 2) is not an isomorphism), and that this is a sufficient
65+ -- but not necessary condition (because 1) is not an isomorphism).
66+ -- Our disjunction loses information, so it makes sense to nest it as
67+ -- deeply as possible, hence we choose the latter representation.
68+ --
69+ -- We delegate the verification of (⋂_j A[j]) ⊂ B to a separate heuristic
70+ -- function, with the understanding that ∃j, A[j] ⊂ B is a sufficient,
71+ -- but not necessary condition (because of 3) and 4)).
72+ --
73+ -- If k ranges over an empty set, we have the isomorphism:
74+ -- (⋃_i ⋂_j A[i,j]) ⊂ ∅ = ∀i, (⋂_j A[i,j]) ⊂ ∅
75+ -- where we again delegate (⋂_j A[j]) ⊂ ∅ to a heuristic, though here the
76+ -- shortcut of ∃j, A[j] ⊂ ∅ hardly helps.
77+ --
78+ -- Disjunctions tend to erase informative error messages, so we may want
79+ -- to avoid them. This can be formally done as follows: if we can
80+ -- partition the universal set into a disjoint union of some parts:
81+ -- ⊤ = ⊔_α P[α]
82+ -- such that the conjuncts in our disjunctive normal form are subordinate
83+ -- to the partition:
84+ -- ∀i ∃α, (⋂_j A[i,j]) ⊂ P[α]
85+ -- ∀k ∃α, (⋂_l B[k,l]) ⊂ P[α]
86+ -- then we can partition the sets over which i and k range into partitions
87+ -- I[α] and K[α], and then in each "bucket" verify the inclusion in the
88+ -- aforementioned way:
89+ -- ∀α, (⋃_i∈I[α] ⋂_j A[i,j]) ⊂ (⋃_k∈K[α] ⋂_l B[k,l])
90+ -- = ∀α ∀i∈I[α] ∃k∈K[α] ∀l, (⋂_j A[i,j]) ⊂ B[k,l]
91+ -- We already somewhat do this by partitioning JSON into types, but we can
92+ -- additionally partition e.g. "enum" fields or existence of particular
93+ -- properties. This works especially well if we manage to ensure K[α] are
94+ -- 1-element sets.
95+ --
96+ -- Since the set:
97+ -- (⋃_i∈I[α] ⋂_j A[i,j]) = (⋃_i ⋂_j A[i,j]) ∩ P[α]
98+ -- does not actually appear in the source schema, we need to construct it
99+ -- ourselves and come up with a name for it.
100+ let typesRestricted = not (anyBottomTypes fp) && anyBottomTypes fc
101+ -- Specifically handle the case when a schema's type has been
102+ -- restricted from "all" to specific types: if all types were allowed
103+ -- in the producer and not all types are allowed in the consumer, it's
104+ -- usually easier to say what's left than what's removed
105+ when typesRestricted $ issueAt beh $ TypesRestricted $ nonBottomTypes fc
106+ forType_ $ \tyName ty -> do
107+ let beh' = beh >>> step (OfType tyName)
108+ case (getJsonFormula $ ty fp, getJsonFormula $ ty fc) of
109+ (DNF pss, BottomDNF) -> unless typesRestricted $ do
110+ -- don't repeat the TypesRestricted issue
111+ for_ pss $ \(Disjunct ps) -> checkContradiction beh' Nothing ps
112+ (DNF pss, SingleDisjunct (Disjunct cs)) -> for_ pss $ \(Disjunct ps) -> do
113+ for_ cs $ checkImplication env beh' trs ps -- avoid disjunction if there's only one conjunct
114+ (TopDNF, DNF css) ->
115+ -- producer is "open" (allows any value), but consumer has restrictions.
116+ -- In this case we want to show which restrictions were added. (instead
117+ -- of showing an empty list restrictions that couldn't be satisfied.)
118+ for_ css $ \(Disjunct cs) -> for_ cs $ checkImplication env beh' trs S.empty
119+ (pss', css') -> for_ (tryPartition defs $ ProdCons (JsonFormula pss') (JsonFormula css')) $ \case
120+ (mPart, ProdCons pf cf) -> do
121+ let beh'' = foldr ((<<<) . step . InPartition) beh' mPart
122+ case (getJsonFormula pf, getJsonFormula cf) of
123+ (DNF pss, BottomDNF) -> for_ pss $ \(Disjunct ps) -> checkContradiction beh' mPart ps
124+ (DNF pss, SingleDisjunct (Disjunct cs)) -> for_ pss $ \(Disjunct ps) -> do
125+ for_ cs $ checkImplication env beh'' trs ps
126+ -- unlucky:
127+ (DNF pss, DNF css) -> for_ pss $ \(Disjunct ps) -> do
128+ anyOfAt
129+ beh'
130+ (issueFromDisjunct Nothing ps)
131+ [for_ cs $ checkImplication env beh' trs ps | Disjunct cs <- S.toList css]
132+ pure ()
133+ where
134+ anyBottomTypes f = getAny $
135+ foldType $ \_ ty -> case getJsonFormula $ ty f of
136+ BottomDNF -> Any True
137+ _ -> mempty
138+ nonBottomTypes f = foldType $ \tyName ty -> case getJsonFormula $ ty f of
139+ BottomDNF -> mempty
140+ _ -> [tyName]
141+ issueFromDisjunct :: Typeable t => Maybe Partition -> S.Set (Condition t) -> Issue 'TypedSchemaLevel
142+ issueFromDisjunct _ ps
143+ | Just e <- findExactly ps
144+ , all (satisfiesTyped e) ps =
145+ EnumDoesntSatisfy $ untypeValue e -- what does this look like when partitioned?
146+ issueFromDisjunct mPart ps = NoMatchingCondition mPart $ SomeCondition <$> S.toList ps
147+
148+checkContradiction ::
149+ Behavior 'TypedSchemaLevel ->
150+ Maybe Partition ->
151+ S.Set (Condition t) ->
152+ SemanticCompatFormula ()
153+checkContradiction beh mPart _ = issueAt beh $ maybe TypeBecomesEmpty PartitionBecomesEmpty mPart -- TODO #70
154+
155+checkImplication ::
156+ (ReassembleHList xs (CheckEnv (Referenced Schema))) =>
157+ HList xs ->
158+ Behavior 'TypedSchemaLevel ->
159+ ProdCons (Trace Schema) -> -- the traces of the root schemas used in this comparison
160+ S.Set (Condition t) ->
161+ Condition t ->
162+ SemanticCompatFormula ()
163+checkImplication env beh trs prods cons = case findExactly prods of
164+ Just e
165+ | all (satisfiesTyped e) prods ->
166+ if satisfiesTyped e cons
167+ then pure ()
168+ else issueAt beh (EnumDoesntSatisfy $ untypeValue e)
169+ | otherwise -> pure () -- vacuously true
170+ Nothing -> case cons of
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)
173+ Maximum m -> foldCheck min m NoMatchingMaximum MatchingMaximumWeak $ \case
174+ Maximum m' -> Just m'
175+ _ -> Nothing
176+ Minimum m -> foldCheck max m (NoMatchingMinimum . coerce) (MatchingMinimumWeak . coerce) $ \case
177+ Minimum m' -> Just m'
178+ _ -> Nothing
179+ MultipleOf m -> foldCheck lcmScientific m NoMatchingMultipleOf MatchingMultipleOfWeak $ \case
180+ MultipleOf m' -> Just m'
181+ _ -> Nothing
182+ NumberFormat f -> case flip any prods $ \case
183+ NumberFormat f' -> f == f'
184+ _ -> False of
185+ True -> pure ()
186+ False -> issueAt beh (NoMatchingFormat f)
187+ MaxLength m -> foldCheck min m NoMatchingMaxLength MatchingMaxLengthWeak $ \case
188+ MaxLength m' -> Just m'
189+ _ -> Nothing
190+ MinLength m -> foldCheck max m NoMatchingMinLength MatchingMinLengthWeak $ \case
191+ MinLength m' -> Just m'
192+ _ -> Nothing
193+ Pattern p -> case flip any prods $ \case
194+ Pattern p' -> p == p'
195+ _ -> False of
196+ True -> pure ()
197+ False -> issueAt beh (NoMatchingPattern p) -- TODO: regex comparison #32
198+ StringFormat f -> case flip any prods $ \case
199+ StringFormat f' -> f == f'
200+ _ -> False of
201+ True -> pure ()
202+ False -> issueAt beh (NoMatchingFormat f)
203+ Items _ cons' -> case foldSome (<>) prods $ \case
204+ Items _ rs -> Just (Just (rs NE.:| []), mempty)
205+ TupleItems (map snd -> fs) -> Just (mempty, Just (fs NE.:| []))
206+ _ -> Nothing of
207+ Just (mItems, Just pfs)
208+ | not $ allSame (length <$> pfs) -> pure () -- vacuously
209+ | let plen = genericLength (NE.head pfs) ->
210+ clarifyIssue (AnItem beh (anIssue TupleToArray)) $
211+ for_ [0 .. plen - 1] $ \i -> do
212+ let prod' = tracedConjunct $ case mItems of
213+ Just prods' -> ((`genericIndex` i) <$> pfs) <> prods'
214+ Nothing -> (`genericIndex` i) <$> pfs
215+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons prod' cons'
216+ Just (Just prods', Nothing) -> do
217+ let prod' = tracedConjunct prods'
218+ checkCompatibility (beh >>> step InItems) env $ ProdCons prod' cons'
219+ _ -> clarifyIssue (AnItem beh (anIssue NoMatchingItems)) $ do
220+ checkCompatibility (beh >>> step InItems) env $ ProdCons prodTopSchema cons'
221+ 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)
223+ MinItems m' -> Just (mempty, Just . Max $ m', mempty, mempty)
224+ MaxItems m' -> Just (mempty, mempty, Just . Min $ m', mempty)
225+ Items _ rs -> Just (mempty, mempty, mempty, Just (rs NE.:| []))
226+ _ -> Nothing of
227+ -- if the length constraints in the producer are contradictory:
228+ Just (_, Just (Max lowest), Just (Min highest), _) | lowest > highest -> pure ()
229+ -- We have an explicit tuple items clause...
230+ Just (Just pfs, Just (Max plen), _, _)
231+ | plen /= genericLength fs -> -- ...of wrong length
232+ issueAt beh (TupleItemsLengthChanged ProdCons {producer = plen, consumer = genericLength fs})
233+ | otherwise ->
234+ for_ [0 .. plen - 1] $ \i -> do
235+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons (tracedConjunct $ (`genericIndex` i) <$> pfs) (fs `genericIndex` i)
236+ -- We have a fixed length array in the producer...
237+ Just (Nothing, Just (Max plen), Just (Min plen'), mProd)
238+ | plen == plen' ->
239+ clarifyIssue (AnItem beh (anIssue ArrayToTuple)) $ case mProd of
240+ _
241+ | plen /= genericLength fs -> -- ...of wrong length
242+ issueAt beh (TupleItemsLengthChanged ProdCons {producer = plen, consumer = genericLength fs})
243+ Just rs -> for_ [0 .. plen - 1] $ \i -> do
244+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons (tracedConjunct rs) (fs `genericIndex` i)
245+ -- ...and no "items" schema
246+ Nothing -> clarifyIssue (AnItem beh (anIssue NoMatchingTupleItems)) $ do
247+ for_ [0 .. plen - 1] $ \i -> do
248+ checkCompatibility (beh >>> step (InItem i)) env $ ProdCons prodTopSchema (fs `genericIndex` i)
249+ _ -> issueAt beh NoMatchingTupleItems
250+ MaxItems m -> foldCheck min m NoMatchingMaxItems MatchingMaxItemsWeak $ \case
251+ MaxItems m' -> Just m'
252+ TupleItems fs -> Just $ toInteger $ length fs
253+ _ -> Nothing
254+ MinItems m -> foldCheck max m NoMatchingMinItems MatchingMinItemsWeak $ \case
255+ MinItems m' -> Just m'
256+ TupleItems fs -> Just $ toInteger $ length fs
257+ _ -> Nothing
258+ UniqueItems -> case flip any prods $ \case
259+ UniqueItems -> True
260+ MaxItems 1 -> True
261+ TupleItems fs | length fs == 1 -> True
262+ _ -> False of
263+ True -> pure ()
264+ False -> issueAt beh NoMatchingUniqueItems
265+ Properties props _ madd -> case foldSome (<>) prods $ \case
266+ Properties props' _ madd' -> Just $ (props', madd') NE.:| []
267+ _ -> Nothing of
268+ Just pm ->
269+ anyOfAt beh NoMatchingProperties $ -- TODO: could first "concat" the lists
270+ NE.toList pm <&> \(props', madd') -> do
271+ for_ (S.fromList $ M.keys props <> M.keys props') $ \k -> do
272+ let beh' = beh >>> step (InProperty k)
273+ go sch sch' = checkCompatibility beh' env (ProdCons sch sch')
274+ case (maybe False propRequired $ M.lookup k props', maybe False propRequired $ M.lookup k props) of
275+ -- producer does not require field, but consumer does (can fail)
276+ (False, True) -> issueAt beh' PropertyNowRequired
277+ _ -> pure ()
278+ case (M.lookup k props', madd', M.lookup k props, madd) of
279+ -- (producer, additional producer, consumer, additional consumer)
280+ (Nothing, Nothing, _, _) -> pure () -- vacuously: the producer asserts that this field cannot exist,
281+ -- and the consumer either doesn't require it, or it does and we've already raised an error about it.
282+ (_, _, Nothing, Nothing) -> issueAt beh' UnexpectedProperty
283+ (Just p', _, Just p, _) -> go (propRefSchema p') (propRefSchema p)
284+ (Nothing, Just add', Just p, _) ->
285+ clarifyIssue (AnItem beh' (anIssue AdditionalToProperty)) $
286+ go add' (propRefSchema p)
287+ (Just p', _, Nothing, Just add) ->
288+ clarifyIssue (AnItem beh' (anIssue PropertyToAdditional)) $
289+ go (propRefSchema p') add
290+ (Nothing, Just _, Nothing, Just _) -> pure ()
291+ pure ()
292+ case (madd', madd) of
293+ (Nothing, _) -> pure () -- vacuously
294+ (_, Nothing) -> issueAt beh NoAdditionalProperties
295+ (Just add', Just add) -> checkCompatibility (beh >>> step InAdditionalProperty) env (ProdCons add' add)
296+ pure ()
297+ Nothing -> issueAt beh NoMatchingProperties
298+ MaxProperties m -> foldCheck min m NoMatchingMaxProperties MatchingMaxPropertiesWeak $ \case
299+ MaxProperties m' -> Just m'
300+ _ -> Nothing
301+ MinProperties m -> foldCheck max m NoMatchingMinProperties MatchingMinPropertiesWeak $ \case
302+ MinProperties m' -> Just m'
303+ _ -> Nothing
304+ where
305+ lcmScientific (toRational -> a) (toRational -> b) =
306+ fromRational $ lcm (numerator a) (numerator b) % gcd (denominator a) (denominator b)
307+
308+ foldCheck ::
309+ Eq a =>
310+ (a -> a -> a) ->
311+ a ->
312+ (a -> Issue 'TypedSchemaLevel) ->
313+ (ProdCons a -> Issue 'TypedSchemaLevel) ->
314+ (forall t. Condition t -> Maybe a) ->
315+ SemanticCompatFormula ()
316+ foldCheck f m missing weak extr = case foldSome f prods extr of
317+ Just m'
318+ | f m' m == m' -> pure ()
319+ | otherwise -> issueAt beh (weak ProdCons {producer = m', consumer = m})
320+ Nothing -> issueAt beh (missing m)
321+
322+ prodTopSchema = traced (producer trs >>> step ImplicitTopSchema) $ Inline mempty
323+
324+allSame :: (Foldable f, Eq a) => f a -> Bool
325+allSame xs = case group (toList xs) of
326+ [] -> True
327+ [_] -> True
328+ _ -> False
329+
330+foldSome :: (b -> b -> b) -> S.Set a -> (a -> Maybe b) -> Maybe b
331+foldSome combine xs extr =
332+ fmap (foldr1 combine) . NE.nonEmpty . mapMaybe extr . S.toList $ xs
333+
334+findExactly :: S.Set (Condition t) -> Maybe (TypedValue t)
335+findExactly xs = foldSome const xs $ \case
336+ Exactly x -> Just x
337+ _ -> Nothing
338+
339+instance Subtree Schema where
340+ type SubtreeLevel Schema = 'SchemaLevel
341+ type CheckEnv Schema = '[ProdCons (Traced (Definitions Schema))]
342+ checkStructuralCompatibility env pc = do
343+ structuralEq $ fmap _schemaRequired <$> pc
344+ structuralEq $ fmap _schemaNullable <$> pc
345+ structuralMaybeWith (structuralList env) $ tracedAllOf <$> pc
346+ structuralMaybeWith (structuralList env) $ tracedOneOf <$> pc
347+ structuralMaybe env $ sequence . stepTraced NotStep . fmap _schemaNot <$> pc
348+ structuralMaybeWith (structuralList env) $ tracedAnyOf <$> pc
349+ iohmStructural env $ stepTraced PropertiesStep . fmap _schemaProperties <$> pc
350+ structuralMaybeWith structuralAdditionalProperties $ tracedAdditionalProperties <$> pc
351+ structuralMaybeWith structuralDiscriminator $ tracedDiscriminator <$> pc
352+ structuralEq $ fmap _schemaReadOnly <$> pc
353+ structuralEq $ fmap _schemaWriteOnly <$> pc
354+ structuralEq $ fmap _schemaXml <$> pc
355+ structuralEq $ fmap _schemaMaxProperties <$> pc
356+ structuralEq $ fmap _schemaMinProperties <$> pc
357+ structuralEq $ fmap _schemaDefault <$> pc
358+ structuralEq $ fmap _schemaType <$> pc
359+ structuralEq $ fmap _schemaFormat <$> pc
360+ structuralMaybeWith structuralItems $ tracedItems <$> pc
361+ structuralEq $ fmap _schemaMaximum <$> pc
362+ structuralEq $ fmap _schemaExclusiveMaximum <$> pc
363+ structuralEq $ fmap _schemaMinimum <$> pc
364+ structuralEq $ fmap _schemaExclusiveMinimum <$> pc
365+ structuralEq $ fmap _schemaMaxLength <$> pc
366+ structuralEq $ fmap _schemaMinLength <$> pc
367+ structuralEq $ fmap _schemaPattern <$> pc
368+ structuralEq $ fmap _schemaMaxItems <$> pc
369+ structuralEq $ fmap _schemaMinItems <$> pc
370+ structuralEq $ fmap _schemaUniqueItems <$> pc
371+ structuralEq $ fmap _schemaEnum <$> pc
372+ structuralEq $ fmap _schemaMultipleOf <$> pc
373+ pure ()
374+ where
375+ structuralAdditionalProperties
376+ (ProdCons (Left x) (Left y)) = unless (x == y) structuralIssue
377+ structuralAdditionalProperties
378+ (ProdCons (Right x) (Right y)) =
379+ checkSubstructure env $ ProdCons x y
380+ structuralAdditionalProperties _ = structuralIssue
381+ structuralDiscriminator pc' = do
382+ structuralEq $ fmap _discriminatorPropertyName <$> pc'
383+ iohmStructural env $
384+ stepTraced DiscriminatorMapping . fmap (fmap parseDiscriminatorValue . _discriminatorMapping) <$> pc'
385+ pure ()
386+ structuralItems (ProdCons (Left a) (Left b)) =
387+ checkSubstructure env $ ProdCons a b
388+ structuralItems (ProdCons (Right a) (Right b)) =
389+ structuralList env $ ProdCons a b
390+ structuralItems _ = structuralIssue
391+ checkSemanticCompatibility env beh schs = do
392+ let defs = getH env
393+ checkFormulas env beh (ask <$> schs) defs $ schemaToFormula <$> defs <*> schs
394+
395+parseDiscriminatorValue :: Text -> Referenced Schema
396+parseDiscriminatorValue v = case A.fromJSON @(Referenced Schema) $ A.object ["$ref" A..= v] of
397+ A.Success x -> x
398+ A.Error _ -> Ref $ Reference v
src/Data/OpenApi/Compare/Validate/Schema/DNF.hsnew file+101
@@ -0,0 +1,101 @@
1+module Data.OpenApi.Compare.Validate.Schema.DNF
2+ ( DNF (..),
3+ Disjunct (..),
4+ pattern SingleDisjunct,
5+ pattern TopDNF,
6+ pattern BottomDNF,
7+ pattern LiteralDNF,
8+ foldDNF,
9+ forDNF,
10+ )
11+where
12+
13+import Algebra.Lattice
14+import Control.Applicative
15+import Data.Foldable
16+import qualified Data.Set as S
17+
18+-- | A boolean formula (without "not") represented as a Disjunctive Normal Form:
19+-- the formula is a disjunction of a set of clauses, each of which is a
20+-- conjunction of a set of some elementary formulas.
21+-- Invariant: no two disjuncts imply eachother
22+newtype DNF a = DNF (S.Set (Disjunct a))
23+ deriving stock (Eq, Ord, Show)
24+
25+-- A disjunct is a thing that is to be disjuncted. Itself it is a conjunction of some literals.
26+newtype Disjunct a = Disjunct (S.Set a)
27+ deriving stock (Eq, Ord, Show)
28+
29+disjImplies :: Ord a => Disjunct a -> Disjunct a -> Bool
30+disjImplies (Disjunct xs) (Disjunct ys) = ys `S.isSubsetOf` xs
31+
32+disjConjunction :: Ord a => Disjunct a -> Disjunct a -> Disjunct a
33+disjConjunction (Disjunct xs) (Disjunct ys) = Disjunct $ xs `S.union` ys
34+
35+disjAdd :: Ord a => DNF a -> Disjunct a -> DNF a
36+disjAdd (DNF yss) xs
37+ | any (xs `disjImplies`) yss = DNF yss
38+ | otherwise = DNF $ S.insert xs $ S.filter (not . (`disjImplies` xs)) yss
39+
40+instance Ord a => Lattice (DNF a) where
41+ xss \/ DNF yss = S.foldl' disjAdd xss yss
42+ DNF xss /\ DNF yss =
43+ foldl' disjAdd bottom $
44+ liftA2 disjConjunction (S.toList xss) (S.toList yss)
45+
46+pattern BottomDNF :: DNF a
47+pattern BottomDNF <-
48+ DNF (S.null -> True)
49+ where
50+ BottomDNF = DNF S.empty
51+
52+isSingleton :: S.Set a -> Maybe a
53+isSingleton s
54+ | S.size s == 1 = S.lookupMin s
55+ | otherwise = Nothing
56+
57+pattern SingleDisjunct :: Ord a => Disjunct a -> DNF a
58+pattern SingleDisjunct xs <-
59+ DNF (isSingleton -> Just xs)
60+ where
61+ SingleDisjunct xs = DNF $ S.singleton xs
62+
63+pattern TopDNF :: DNF a
64+pattern TopDNF <-
65+ DNF (isSingleton -> Just (Disjunct (S.null -> True)))
66+ where
67+ TopDNF = DNF $ S.singleton $ Disjunct S.empty
68+
69+pattern LiteralDNF :: Ord a => a -> DNF a
70+pattern LiteralDNF x <-
71+ SingleDisjunct (Disjunct (isSingleton -> Just x))
72+ where
73+ LiteralDNF x = SingleDisjunct $ Disjunct $ S.singleton x
74+
75+instance Ord a => BoundedJoinSemiLattice (DNF a) where
76+ bottom = BottomDNF
77+
78+instance Ord a => BoundedMeetSemiLattice (DNF a) where
79+ top = TopDNF
80+
81+foldDisjunct :: BoundedMeetSemiLattice l => (a -> l) -> Disjunct a -> l
82+foldDisjunct f (Disjunct xs) = S.foldl' (\y l -> y /\ f l) top xs
83+
84+foldDNF :: BoundedLattice l => (a -> l) -> DNF a -> l
85+foldDNF f (DNF xss) = S.foldl' (\y xs -> y \/ foldDisjunct f xs) bottom xss
86+
87+newtype LiftA f a = LiftA {getLiftA :: f a}
88+ deriving newtype (Functor, Applicative)
89+
90+instance (Lattice a, Applicative f) => Lattice (LiftA f a) where
91+ (/\) = liftA2 (/\)
92+ (\/) = liftA2 (\/)
93+
94+instance (BoundedJoinSemiLattice a, Applicative f) => BoundedJoinSemiLattice (LiftA f a) where
95+ bottom = pure bottom
96+
97+instance (BoundedMeetSemiLattice a, Applicative f) => BoundedMeetSemiLattice (LiftA f a) where
98+ top = pure top
99+
100+forDNF :: (BoundedLattice l, Applicative f) => (a -> f l) -> DNF a -> f l
101+forDNF f = getLiftA . foldDNF (LiftA . f)
src/Data/OpenApi/Compare/Validate/Schema/Issues.hsnew file+321
@@ -0,0 +1,321 @@
1+{-# OPTIONS_GHC -Wno-orphans #-}
2+
3+module Data.OpenApi.Compare.Validate.Schema.Issues
4+ ( Issue (..),
5+ Behave (..),
6+ )
7+where
8+
9+import qualified Data.Aeson as A
10+import Data.OpenApi
11+import Data.OpenApi.Compare.Behavior
12+import Data.OpenApi.Compare.Subtree
13+import Data.OpenApi.Compare.Validate.Schema.JsonFormula
14+import Data.OpenApi.Compare.Validate.Schema.Partition
15+import Data.OpenApi.Compare.Validate.Schema.TypedJson
16+import Data.Scientific
17+import Data.Text (Text)
18+import qualified Data.Text as T
19+import Text.Pandoc.Builder hiding (Format, Null)
20+
21+instance Issuable 'TypedSchemaLevel where
22+ data Issue 'TypedSchemaLevel
23+ = -- | producer produces a specific value ($1), consumer has a condition that is not satisfied by said value
24+ EnumDoesntSatisfy A.Value
25+ | -- | consumer only expects a specific value which the producer does not produce.
26+ NoMatchingEnum A.Value
27+ | -- | consumer declares a maximum numeric value ($1), producer doesn't
28+ NoMatchingMaximum (Bound Scientific)
29+ | -- | consumer declares a maximum numeric value ($1), producer declares a weaker (higher) limit ($2)
30+ MatchingMaximumWeak (ProdCons (Bound Scientific))
31+ | -- | consumer declares a minimum numeric value, producer doesn't
32+ NoMatchingMinimum (Bound Scientific)
33+ | -- | consumer declares a minimum numeric value ($1), producer declares a weaker (lower) limit ($2)
34+ MatchingMinimumWeak (ProdCons (Bound Scientific))
35+ | -- | consumer declares that the numeric value must be a multiple of $1, producer doesn't
36+ NoMatchingMultipleOf Scientific
37+ | -- | consumer declares that the numeric value must be a multiple of $1, producer declares a weaker condition (multiple of $2)
38+ MatchingMultipleOfWeak (ProdCons Scientific)
39+ | -- | consumer declares a string/number format, producer declares none or a different format (TODO: improve via regex #32)
40+ NoMatchingFormat Format
41+ | -- | consumer declares a maximum length of the string ($1), producer doesn't.
42+ NoMatchingMaxLength Integer
43+ | -- | consumer declares a maximum length of the string ($1), producer declares a weaker (higher) limit ($2)
44+ MatchingMaxLengthWeak (ProdCons Integer)
45+ | -- | consumer declares a minimum length of the string ($1), producer doesn't.
46+ NoMatchingMinLength Integer
47+ | -- | consumer declares a minimum length of the string ($1), producer declares a weaker (lower) limit ($2)
48+ MatchingMinLengthWeak (ProdCons Integer)
49+ | -- | consumer declares the string value must match a regex ($1), producer doesn't declare or declares different regex (TODO: #32)
50+ NoMatchingPattern Pattern
51+ | -- | consumer declares the items of an array must satisfy some condition, producer doesn't
52+ NoMatchingItems
53+ | -- | producer and consumer declare that an array must be a tuple of a fixed length, but the lengths don't match
54+ TupleItemsLengthChanged (ProdCons Integer)
55+ | -- | consumer declares that the array is a tuple, but the producer doesn't, the length constraints match, but there were issues with the components
56+ ArrayToTuple
57+ | -- | producer declares that the array is a tuple, but the consumer doesn't, and there were issues with the components
58+ TupleToArray
59+ | -- | consumer declares that the array is a tuple, but the producer doesn't, and there aren't sufficient length constraints
60+ NoMatchingTupleItems
61+ | -- | consumer declares a maximum length of the array ($1), producer doesn't.
62+ NoMatchingMaxItems Integer
63+ | -- | consumer declares a maximum length of the array ($1), producer declares a weaker (higher) limit ($2)
64+ MatchingMaxItemsWeak (ProdCons Integer)
65+ | -- | consumer declares a minimum length of the array ($1), producer doesn't.
66+ NoMatchingMinItems Integer
67+ | -- | consumer declares a minimum length of the array ($1), producer declares a weaker (lower) limit ($2)
68+ MatchingMinItemsWeak (ProdCons Integer)
69+ | -- | consumer declares that items must be unique, producer doesn't
70+ NoMatchingUniqueItems
71+ | -- | consumer declares the properties of an object must satisfy some condition, producer doesn't
72+ NoMatchingProperties
73+ | -- | producer allows additional properties, consumer doesn't
74+ NoAdditionalProperties
75+ | -- | consumer declares a maximum number of properties in the object ($1), producer doesn't.
76+ NoMatchingMaxProperties Integer
77+ | -- | consumer declares a maximum number of properties in the object ($1), producer declares a weaker (higher) limit ($2)
78+ MatchingMaxPropertiesWeak (ProdCons Integer)
79+ | -- | consumer declares a minimum number of properties in the object ($1), producer doesn't.
80+ NoMatchingMinProperties Integer
81+ | -- | consumer declares a minimum number of properties in the object ($1), producer declares a weaker (lower) limit ($2)
82+ MatchingMinPropertiesWeak (ProdCons Integer)
83+ | -- | producer declares that the value must satisfy a disjunction of some conditions, but consumer's requirements couldn't be matched against any single one of them (TODO: split heuristic #71)
84+ NoMatchingCondition (Maybe Partition) [SomeCondition]
85+ | -- | consumer indicates that no values of this type are allowed, but we weren't able to conclude that in the producer (currently only immediate contradictions are checked, c.f. #70)
86+ TypeBecomesEmpty
87+ | -- | consumer indicates that no values in a particular partition are allowed, but we weren't able to conclude this in the producer
88+ PartitionBecomesEmpty Partition
89+ deriving stock (Eq, Ord, Show)
90+ issueKind = \case
91+ NoMatchingEnum _ -> ProbablyIssue
92+ MatchingMaximumWeak _ -> ProbablyIssue -- interplay with MultipleOf could make this not an issue
93+ MatchingMinimumWeak _ -> ProbablyIssue -- ditto
94+ MatchingMultipleOfWeak _ -> ProbablyIssue -- ditto
95+ NoMatchingFormat _ -> Unsupported
96+ NoMatchingPattern _ -> Unsupported
97+ ArrayToTuple -> Comment
98+ TupleToArray -> Comment
99+ NoMatchingProperties -> ProbablyIssue -- TODO: #109
100+ TypeBecomesEmpty -> ProbablyIssue -- TODO: #70
101+ PartitionBecomesEmpty _ -> ProbablyIssue -- ditto
102+ _ -> CertainIssue
103+ relatedIssues =
104+ (==) `withClass` \case
105+ EnumDoesntSatisfy v -> Just v
106+ NoMatchingEnum v -> Just v
107+ _ -> Nothing
108+ `withClass` \case
109+ NoMatchingMaximum _ -> Just ()
110+ MatchingMaximumWeak _ -> Just ()
111+ _ -> Nothing
112+ `withClass` \case
113+ NoMatchingMinimum _ -> Just ()
114+ MatchingMinimumWeak _ -> Just ()
115+ _ -> Nothing
116+ `withClass` \case
117+ NoMatchingMultipleOf _ -> Just ()
118+ MatchingMultipleOfWeak _ -> Just ()
119+ _ -> Nothing
120+ `withClass` \case
121+ NoMatchingMaxLength _ -> Just ()
122+ MatchingMaxLengthWeak _ -> Just ()
123+ _ -> Nothing
124+ `withClass` \case
125+ NoMatchingMinLength _ -> Just ()
126+ MatchingMinLengthWeak _ -> Just ()
127+ _ -> Nothing
128+ `withClass` \case
129+ NoMatchingItems -> Just ()
130+ ArrayToTuple -> Just ()
131+ TupleToArray -> Just ()
132+ NoMatchingTupleItems -> Just ()
133+ TupleItemsLengthChanged _ -> Just ()
134+ _ -> Nothing
135+ `withClass` \case
136+ NoMatchingMaxItems _ -> Just ()
137+ MatchingMaxItemsWeak _ -> Just ()
138+ _ -> Nothing
139+ `withClass` \case
140+ NoMatchingMinItems _ -> Just ()
141+ MatchingMinItemsWeak _ -> Just ()
142+ _ -> Nothing
143+ `withClass` \case
144+ NoMatchingMaxProperties _ -> Just ()
145+ MatchingMaxPropertiesWeak _ -> Just ()
146+ _ -> Nothing
147+ `withClass` \case
148+ NoMatchingMinProperties _ -> Just ()
149+ MatchingMinPropertiesWeak _ -> Just ()
150+ _ -> Nothing
151+ 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
153+ describeIssue Forward (NoMatchingEnum v) = para "The following enum value has been added:" <> showJSONValue v
154+ describeIssue Backward (NoMatchingEnum v) = para "The following enum value has been removed:" <> showJSONValue v
155+ describeIssue Forward (NoMatchingMaximum b) = para $ "Upper bound has been added:" <> showBound b <> "."
156+ describeIssue Backward (NoMatchingMaximum b) = para $ "Upper bound has been removed:" <> showBound b <> "."
157+ describeIssue ori (MatchingMaximumWeak (orientProdCons ori -> ProdCons p c)) =
158+ para $ "Upper bound changed from " <> showBound p <> " to " <> showBound c <> "."
159+ describeIssue Forward (NoMatchingMinimum b) = para $ "Lower bound has been added: " <> showBound b <> "."
160+ describeIssue Backward (NoMatchingMinimum b) = para $ "Lower bound has been removed: " <> showBound b <> "."
161+ describeIssue ori (MatchingMinimumWeak (orientProdCons ori -> ProdCons p c)) =
162+ para $ "Lower bound changed from " <> showBound p <> " to " <> showBound c <> "."
163+ describeIssue Forward (NoMatchingMultipleOf n) = para $ "Value is now a multiple of " <> show' n <> "."
164+ describeIssue Backward (NoMatchingMultipleOf n) = para $ "Value is no longer a multiple of " <> show' n <> "."
165+ describeIssue ori (MatchingMultipleOfWeak (orientProdCons ori -> ProdCons p c)) =
166+ para $ "Value changed from being a multiple of " <> show' p <> " to being a multiple of " <> show' c <> "."
167+ describeIssue Forward (NoMatchingFormat f) = para $ "Format added: " <> code f <> "."
168+ describeIssue Backward (NoMatchingFormat f) = para $ "Format removed: " <> code f <> "."
169+ describeIssue Forward (NoMatchingMaxLength n) = para $ "Maximum length added: " <> show' n <> "."
170+ describeIssue Backward (NoMatchingMaxLength n) = para $ "Maximum length removed: " <> show' n <> "."
171+ describeIssue ori (MatchingMaxLengthWeak (orientProdCons ori -> ProdCons p c)) =
172+ para $ "Maximum length of the string changed from " <> show' p <> " to " <> show' c <> "."
173+ describeIssue Forward (NoMatchingMinLength n) = para $ "Minimum length of the string added: " <> show' n <> "."
174+ describeIssue Backward (NoMatchingMinLength n) = para $ "Minimum length of the string removed: " <> show' n <> "."
175+ describeIssue ori (MatchingMinLengthWeak (orientProdCons ori -> ProdCons p c)) =
176+ para $ "Minimum length of the string changed from " <> show' p <> " to " <> show' c <> "."
177+ describeIssue Forward (NoMatchingPattern p) = para "Pattern (regular expression) added: " <> codeBlock p
178+ describeIssue Backward (NoMatchingPattern p) = para "Pattern (regular expression) removed: " <> codeBlock p
179+ describeIssue Forward NoMatchingItems = para "Array item schema has been added."
180+ describeIssue Backward NoMatchingItems = para "Array item schema has been removed."
181+ describeIssue ori (TupleItemsLengthChanged (orientProdCons ori -> ProdCons p c)) =
182+ para $ "Tuple length changed from " <> show' p <> " to " <> show' c <> "."
183+ describeIssue Forward ArrayToTuple = para "The array is now explicitly defined as a tuple."
184+ describeIssue Backward ArrayToTuple = para "The array is no longer explicitly defined as a tuple."
185+ describeIssue Forward TupleToArray = para "The array is no longer explicitly defined as a tuple."
186+ describeIssue Backward TupleToArray = para "The array is now explicitly defined as a tuple."
187+ describeIssue Forward NoMatchingTupleItems = para "The array is now explicitly defined as a tuple."
188+ describeIssue Backward NoMatchingTupleItems = para "The array is no longer explicitly defined as a tuple."
189+ describeIssue Forward (NoMatchingMaxItems n) = para $ "Maximum length of the array has been added " <> show' n <> "."
190+ describeIssue Backward (NoMatchingMaxItems n) = para $ "Maximum length of the array has been removed " <> show' n <> "."
191+ describeIssue ori (MatchingMaxItemsWeak (orientProdCons ori -> ProdCons p c)) =
192+ para $ "Maximum length of the array changed from " <> show' p <> " to " <> show' c <> "."
193+ describeIssue Forward (NoMatchingMinItems n) = para $ "Minimum length of the array added: " <> show' n <> "."
194+ describeIssue Backward (NoMatchingMinItems n) = para $ "Minimum length of the array removed: " <> show' n <> "."
195+ describeIssue ori (MatchingMinItemsWeak (orientProdCons ori -> ProdCons p c)) =
196+ para $ "Minimum length of the array changed from " <> show' p <> " to " <> show' c <> "."
197+ describeIssue Forward NoMatchingUniqueItems = para "Items are now required to be unique."
198+ describeIssue Backward NoMatchingUniqueItems = para "Items are no longer required to be unique."
199+ describeIssue Forward NoMatchingProperties = para "Property added."
200+ describeIssue Backward NoMatchingProperties = para "Property removed."
201+ describeIssue Forward NoAdditionalProperties = para "Additional properties have been removed."
202+ describeIssue Backward NoAdditionalProperties = para "Additional properties have been added."
203+ describeIssue Forward (NoMatchingMaxProperties n) = para $ "Maximum number of properties has been added: " <> show' n <> "."
204+ describeIssue Backward (NoMatchingMaxProperties n) = para $ "Maximum number of properties has been removed: " <> show' n <> "."
205+ describeIssue ori (MatchingMaxPropertiesWeak (orientProdCons ori -> ProdCons p c)) =
206+ para $ "Maximum number of properties has changed from " <> show' p <> " to " <> show' c <> "."
207+ describeIssue Forward (NoMatchingMinProperties n) = para $ "Minimum number of properties added: " <> show' n <> "."
208+ describeIssue Backward (NoMatchingMinProperties n) = para $ "Minimum number of properties removed: " <> show' n <> "."
209+ describeIssue ori (MatchingMinPropertiesWeak (orientProdCons ori -> ProdCons p c)) =
210+ para $ "Minimum number of properties has changed from " <> show' p <> " to " <> show' c <> "."
211+ describeIssue _ (NoMatchingCondition mPart conds) =
212+ para
213+ ( case mPart of
214+ Nothing -> "Could not verify that the following conditions hold (please file a bug if you see this):"
215+ Just locPart ->
216+ "In cases where " <> showPartition locPart
217+ <> " – could not verify that the following conditions hold (please file a bug if you see this):"
218+ )
219+ <> bulletList ((\(SomeCondition c) -> showCondition c) <$> conds)
220+ describeIssue Forward TypeBecomesEmpty = para "The type has been removed."
221+ describeIssue Backward TypeBecomesEmpty = para "The type has been added."
222+ describeIssue Forward (PartitionBecomesEmpty part) = para $ "The case where " <> showPartition part <> " – has been removed."
223+ describeIssue Backward (PartitionBecomesEmpty part) = para $ "The case where " <> showPartition part <> " – has been added."
224+
225+show' :: Show x => x -> Inlines
226+show' = str . T.pack . show
227+
228+instance Issuable 'SchemaLevel where
229+ data Issue 'SchemaLevel
230+ = -- | Some (openapi-supported) feature that we do not support was encountered in the schema
231+ NotSupported Text
232+ | -- | We couldn't prove that the branches of a oneOf are disjoint, and we will treat it as an anyOf, meaning we don't check whether the overlaps are excluded in a compatible way
233+ OneOfNotDisjoint
234+ | -- | The schema is actually invalid
235+ InvalidSchema Text
236+ | -- | The schema contains a reference loop along "anyOf"/"allOf"/"oneOf".
237+ UnguardedRecursion
238+ | -- | Producer doesn't place any restrictions on the types, but the consumer does. List what types remain available in the consumer.
239+ TypesRestricted [JsonType]
240+ | -- | in the producer this field used to be handled as part of "additionalProperties", and the consumer this is a specific "properties" entry. Only thrown when this change actually causes other issues
241+ AdditionalToProperty
242+ | -- | in the consumer this field used to be handled as part of "additionalProperties", and the producer this is a specific "properties" entry. Only thrown when this change actually causes other issues
243+ PropertyToAdditional
244+ | -- | consumer requires a property that is not required/allowed in the producer
245+ PropertyNowRequired
246+ | -- | producer allows a property that is not allowed in the consumer
247+ UnexpectedProperty
248+ deriving stock (Eq, Ord, Show)
249+ issueKind = \case
250+ NotSupported _ -> Unsupported
251+ OneOfNotDisjoint -> Unsupported
252+ InvalidSchema _ -> SchemaInvalid
253+ UnguardedRecursion -> Unsupported
254+ AdditionalToProperty -> Comment
255+ PropertyToAdditional -> Comment
256+ TypesRestricted _ -> ProbablyIssue -- TODO: #70
257+ _ -> CertainIssue
258+ relatedIssues =
259+ (==) `withClass` \case
260+ AdditionalToProperty -> Just ()
261+ PropertyToAdditional -> Just ()
262+ _ -> Nothing
263+ `withClass` \case
264+ PropertyNowRequired -> Just ()
265+ UnexpectedProperty -> Just ()
266+ _ -> Nothing
267+ describeIssue _ (NotSupported i) =
268+ para (emph "Encountered a feature that CompaREST does not support: " <> text i <> ".")
269+ describeIssue _ OneOfNotDisjoint =
270+ para $
271+ "Could not deduce that " <> code "oneOf"
272+ <> " cases don't overlap. Treating the "
273+ <> code "oneOf"
274+ <> " as an "
275+ <> code "anyOf"
276+ <> ". Reported errors might not be accurate."
277+ describeIssue _ (InvalidSchema i) =
278+ para (emph "The schema is invalid: " <> text i <> ".")
279+ describeIssue _ UnguardedRecursion =
280+ para "Encountered recursion that is too complex for CompaREST to untangle."
281+ describeIssue Forward (TypesRestricted tys) = case tys of
282+ [] -> para "No longer has any valid values." -- weird
283+ _ -> para "Values are now limited to the following types: " <> bulletList (para . describeJSONType <$> tys)
284+ describeIssue Backward (TypesRestricted tys) = case tys of
285+ [] -> para "Any value of any type is now allowed." -- weird
286+ _ -> para "Values are no longer limited to the following types: " <> bulletList (para . describeJSONType <$> tys)
287+ describeIssue Forward AdditionalToProperty = para "The property was previously implicitly described by the catch-all \"additional properties\" case. It is now explicitly defined."
288+ describeIssue Backward AdditionalToProperty = para "The property was previously explicitly defined. It is now implicitly described by the catch-all \"additional properties\" case."
289+ describeIssue Forward PropertyToAdditional = para "The property was previously explicitly defined. It is now implicitly described by the catch-all \"additional properties\" case."
290+ describeIssue Backward PropertyToAdditional = para "The property was previously implicitly described by the catch-all \"additional properties\" case. It is now explicitly defined."
291+ describeIssue Forward PropertyNowRequired = para "The property has become required."
292+ describeIssue Backward PropertyNowRequired = para "The property may not be present."
293+ describeIssue Forward UnexpectedProperty = para "The property has been removed."
294+ describeIssue Backward UnexpectedProperty = para "The property has been added."
295+
296+instance Behavable 'SchemaLevel 'TypedSchemaLevel where
297+ data Behave 'SchemaLevel 'TypedSchemaLevel
298+ = OfType JsonType
299+ deriving stock (Eq, Ord, Show)
300+
301+ describeBehavior (OfType t) = describeJSONType t
302+
303+instance Behavable 'TypedSchemaLevel 'TypedSchemaLevel where
304+ data Behave 'TypedSchemaLevel 'TypedSchemaLevel
305+ = InPartition Partition
306+ deriving stock (Eq, Ord, Show)
307+
308+ describeBehavior (InPartition partition) = "In cases where " <> showPartition partition
309+
310+instance Behavable 'TypedSchemaLevel 'SchemaLevel where
311+ data Behave 'TypedSchemaLevel 'SchemaLevel
312+ = InItems
313+ | InItem Integer
314+ | InProperty Text
315+ | InAdditionalProperty
316+ deriving stock (Eq, Ord, Show)
317+
318+ describeBehavior InItems = "Items"
319+ describeBehavior (InItem i) = "Item " <> show' i
320+ describeBehavior (InProperty p) = "Property " <> code p
321+ describeBehavior InAdditionalProperty = "Additional properties"
src/Data/OpenApi/Compare/Validate/Schema/JsonFormula.hsnew file+237
@@ -0,0 +1,237 @@
1+module Data.OpenApi.Compare.Validate.Schema.JsonFormula
2+ ( Bound (..),
3+ showBound,
4+ Property (..),
5+ Condition (..),
6+ showCondition,
7+ satisfiesTyped,
8+ checkStringFormat,
9+ checkNumberFormat,
10+ SomeCondition (..),
11+ JsonFormula (..),
12+ satisfiesFormula,
13+ satisfies,
14+ showJSONValue,
15+ showJSONValueInline,
16+ )
17+where
18+
19+import Algebra.Lattice
20+import qualified Data.Aeson as A
21+import qualified Data.Aeson.Key as Key
22+import qualified Data.Aeson.KeyMap as KeyMap
23+import qualified Data.ByteString.Lazy as BSL
24+import qualified Data.Foldable as F
25+import Data.Functor
26+import Data.Int
27+import Data.Kind
28+import qualified Data.Map as M
29+import Data.Maybe
30+import Data.OpenApi
31+import Data.OpenApi.Compare.Orphans ()
32+import Data.OpenApi.Compare.Subtree
33+import Data.OpenApi.Compare.Validate.Schema.DNF
34+import Data.OpenApi.Compare.Validate.Schema.TypedJson
35+import Data.Ord
36+import Data.Ratio
37+import Data.Scientific
38+import qualified Data.Set as S
39+import Data.Text (Text)
40+import qualified Data.Text as T
41+import qualified Data.Text.Encoding as T
42+import Data.Typeable
43+import Text.Pandoc.Builder hiding (Format)
44+import Text.Regex.Pcre2
45+
46+data Bound a = Exclusive !a | Inclusive !a
47+ deriving stock (Eq, Show, Functor)
48+
49+-- | The order is lexicographical on @a * Bool@.
50+instance Ord a => Ord (Bound a) where
51+ Exclusive a `compare` Exclusive b = compare a b
52+ Exclusive a `compare` Inclusive b = if a <= b then LT else GT
53+ Inclusive a `compare` Exclusive b = if a < b then LT else GT
54+ Inclusive a `compare` Inclusive b = compare a b
55+
56+showBound :: Show a => Bound a -> Inlines
57+showBound (Inclusive x) = show' x <> " inclusive"
58+showBound (Exclusive x) = show' x <> " exclusive"
59+
60+data Property = Property
61+ { propRequired :: Bool
62+ , propFormula :: ForeachType JsonFormula
63+ , propRefSchema :: Traced (Referenced Schema)
64+ }
65+ deriving stock (Eq, Ord, Show)
66+
67+-- | A primitive structural condition for the "top level" of a JSON value (of a specific type)
68+data Condition :: JsonType -> Type where
69+ Exactly :: TypedValue t -> Condition t
70+ Maximum :: !(Bound Scientific) -> Condition 'Number
71+ Minimum ::
72+ !(Down (Bound (Down Scientific))) ->
73+ -- | this has the right Ord
74+ Condition 'Number
75+ MultipleOf :: !Scientific -> Condition 'Number
76+ NumberFormat :: !Format -> Condition 'Number
77+ MaxLength :: !Integer -> Condition 'String
78+ MinLength :: !Integer -> Condition 'String
79+ Pattern :: !Pattern -> Condition 'String
80+ StringFormat :: !Format -> Condition 'String
81+ Items ::
82+ !(ForeachType JsonFormula) ->
83+ !(Traced (Referenced Schema)) ->
84+ Condition 'Array
85+ TupleItems ::
86+ ![(ForeachType JsonFormula, Traced (Referenced Schema))] ->
87+ Condition 'Array
88+ MaxItems :: !Integer -> Condition 'Array
89+ MinItems :: !Integer -> Condition 'Array
90+ UniqueItems :: Condition 'Array
91+ Properties ::
92+ !(M.Map Text Property) ->
93+ -- | formula for additional properties
94+ !(ForeachType JsonFormula) ->
95+ -- | schema for additional properties, Nothing means bottom
96+ !(Maybe (Traced (Referenced Schema))) ->
97+ Condition 'Object
98+ MaxProperties :: !Integer -> Condition 'Object
99+ MinProperties :: !Integer -> Condition 'Object
100+
101+deriving stock instance Eq (Condition t)
102+
103+deriving stock instance Ord (Condition t)
104+
105+deriving stock instance Show (Condition t)
106+
107+showCondition :: Condition a -> Blocks
108+showCondition = \case
109+ (Exactly v) -> para "The value should be:" <> showJSONValue (untypeValue v)
110+ (Maximum b) -> para $ "The value should be less than " <> showBound b <> "."
111+ (Minimum (Down b)) -> para $ "The value should be more than " <> showBound (getDown <$> b) <> "."
112+ (MultipleOf n) -> para $ "The value should be a multiple of " <> show' n <> "."
113+ (NumberFormat p) -> para $ "The number should have the following format:" <> code p <> "."
114+ (Pattern p) -> para "The value should satisfy the following pattern (regular expression):" <> codeBlock p
115+ (StringFormat p) -> para $ "The string should have the following format:" <> code p <> "."
116+ (MaxLength p) -> para $ "The length of the string should be less than or equal to " <> show' p <> "."
117+ (MinLength p) -> para $ "The length of the string should be more than or equal to " <> show' p <> "."
118+ (Items i _) -> para "The items of the array should satisfy:" <> showForEachJsonFormula i
119+ (TupleItems is) -> para ("There should be " <> show' (length is) <> " items in the array:") <> bulletList (showForEachJsonFormula . fst <$> is)
120+ (MaxItems n) -> para $ "The length of the array should be less than or equal to " <> show' n <> "."
121+ (MinItems n) -> para $ "The length of the array should be more than or equal to " <> show' n <> "."
122+ UniqueItems -> para "The elements in the array should be unique."
123+ (Properties props additional _) ->
124+ bulletList $
125+ ( M.toList props
126+ <&> ( \(k, p) ->
127+ para (code k)
128+ <> para (strong $ if propRequired p then "Required" else "Optional")
129+ <> showForEachJsonFormula (propFormula p)
130+ )
131+ )
132+ <> [ para (emph "Additional properties")
133+ <> showForEachJsonFormula additional
134+ ]
135+ (MaxProperties n) -> para $ "The maximum number of fields should be " <> show' n <> "."
136+ (MinProperties n) -> para $ "The minimum number of fields should be " <> show' n <> "."
137+ where
138+ showForEachJsonFormula :: ForeachType JsonFormula -> Blocks
139+ showForEachJsonFormula i =
140+ bulletList $
141+ foldType
142+ ( \t f -> case getJsonFormula $ f i of
143+ BottomDNF -> mempty
144+ (DNF conds) ->
145+ [ para (describeJSONType t)
146+ <> bulletList
147+ ( S.toList conds <&> \case
148+ Disjunct (S.toList -> []) -> para "Empty"
149+ Disjunct (S.toList -> cond) -> bulletList (showCondition <$> cond)
150+ )
151+ ]
152+ )
153+
154+showJSONValue :: A.Value -> Blocks
155+showJSONValue v = codeBlockWith ("", ["json"], mempty) (T.decodeUtf8 . BSL.toStrict . A.encode $ v)
156+
157+showJSONValueInline :: A.Value -> Inlines
158+showJSONValueInline v = code (T.decodeUtf8 . BSL.toStrict . A.encode $ v)
159+
160+show' :: Show x => x -> Inlines
161+show' = str . T.pack . show
162+
163+satisfiesTyped :: TypedValue t -> Condition t -> Bool
164+satisfiesTyped e (Exactly e') = e == e'
165+satisfiesTyped (TNumber n) (Maximum (Exclusive m)) = n < m
166+satisfiesTyped (TNumber n) (Maximum (Inclusive m)) = n <= m
167+satisfiesTyped (TNumber n) (Minimum (Down (Exclusive (Down m)))) = n > m
168+satisfiesTyped (TNumber n) (Minimum (Down (Inclusive (Down m)))) = n >= m
169+satisfiesTyped (TNumber n) (MultipleOf m) = denominator (toRational n / toRational m) == 1 -- TODO: could be better #36
170+satisfiesTyped (TNumber n) (NumberFormat f) = checkNumberFormat f n
171+satisfiesTyped (TString s) (MaxLength m) = fromIntegral (T.length s) <= m
172+satisfiesTyped (TString s) (MinLength m) = fromIntegral (T.length s) >= m
173+satisfiesTyped (TString s) (Pattern p) = isJust $ match p s -- TODO: regex stuff #32
174+satisfiesTyped (TString s) (StringFormat f) = checkStringFormat f s
175+satisfiesTyped (TArray a) (Items f _) = all (`satisfies` f) a
176+satisfiesTyped (TArray a) (TupleItems fs) = length fs == F.length a && and (zipWith satisfies (F.toList a) (fst <$> fs))
177+satisfiesTyped (TArray a) (MaxItems m) = fromIntegral (F.length a) <= m
178+satisfiesTyped (TArray a) (MinItems m) = fromIntegral (F.length a) >= m
179+satisfiesTyped (TArray a) UniqueItems = S.size (S.fromList $ F.toList a) == F.length a -- TODO: could be better #36
180+satisfiesTyped (TObject o) (Properties props additional _) =
181+ all (`KeyMap.member` o) (map Key.fromText $ M.keys (M.filter propRequired props))
182+ && all (\(k, v) -> satisfies v $ maybe additional propFormula $ M.lookup (Key.toText k) props) (KeyMap.toList o)
183+satisfiesTyped (TObject o) (MaxProperties m) = fromIntegral (KeyMap.size o) <= m
184+satisfiesTyped (TObject o) (MinProperties m) = fromIntegral (KeyMap.size o) >= m
185+
186+checkNumberFormat :: Format -> Scientific -> Bool
187+checkNumberFormat "int32" (toRational -> n) =
188+ denominator n == 1
189+ && n >= toRational (minBound :: Int32)
190+ && n <= toRational (maxBound :: Int32)
191+checkNumberFormat "int64" (toRational -> n) =
192+ denominator n == 1
193+ && n >= toRational (minBound :: Int64)
194+ && n <= toRational (maxBound :: Int64)
195+checkNumberFormat "float" _n = True
196+checkNumberFormat "double" _n = True
197+checkNumberFormat f _n = error $ "Invalid number format: " <> T.unpack f
198+
199+checkStringFormat :: Format -> Text -> Bool
200+checkStringFormat "byte" _s = True -- TODO: regex stuff #32
201+checkStringFormat "binary" _s = True
202+checkStringFormat "date" _s = True
203+checkStringFormat "date-time" _s = True
204+checkStringFormat "password" _s = True
205+checkStringFormat "uuid" _s = True
206+checkStringFormat f _s = error $ "Invalid string format: " <> T.unpack f
207+
208+data SomeCondition where
209+ SomeCondition :: Typeable t => Condition t -> SomeCondition
210+
211+instance Eq SomeCondition where
212+ SomeCondition x == SomeCondition y = case cast x of
213+ Just x' -> x' == y
214+ Nothing -> False
215+
216+instance Ord SomeCondition where
217+ compare (SomeCondition x) (SomeCondition y) = case cast x of
218+ Just x' -> compare x' y
219+ Nothing -> compare (typeRep x) (typeRep y)
220+
221+deriving stock instance Show SomeCondition
222+
223+newtype JsonFormula t = JsonFormula {getJsonFormula :: DNF (Condition t)}
224+ deriving stock (Eq, Ord, Show)
225+ deriving newtype (Lattice, BoundedJoinSemiLattice, BoundedMeetSemiLattice)
226+
227+satisfiesFormula :: TypedValue t -> JsonFormula t -> Bool
228+satisfiesFormula val = foldDNF (satisfiesTyped val) . getJsonFormula
229+
230+satisfies :: A.Value -> ForeachType JsonFormula -> Bool
231+satisfies val p = case val of
232+ A.Null -> satisfiesFormula TNull $ forNull p
233+ A.Bool b -> satisfiesFormula (TBool b) $ forBoolean p
234+ A.Number n -> satisfiesFormula (TNumber n) $ forNumber p
235+ A.String s -> satisfiesFormula (TString s) $ forString p
236+ A.Array a -> satisfiesFormula (TArray a) $ forArray p
237+ A.Object o -> satisfiesFormula (TObject o) $ forObject p
src/Data/OpenApi/Compare/Validate/Schema/Partition.hsnew file+320
@@ -0,0 +1,320 @@
1+module Data.OpenApi.Compare.Validate.Schema.Partition
2+ ( partitionSchema,
3+ partitionRefSchema,
4+ selectPartition,
5+ runPartitionM,
6+ tryPartition,
7+ showPartition,
8+ intersectSchema,
9+ intersectRefSchema,
10+ IntersectionResult (..),
11+ runIntersectionM,
12+ Partition,
13+ )
14+where
15+
16+import Algebra.Lattice
17+import Algebra.Lattice.Lifted
18+import Control.Applicative
19+import Control.Monad (when)
20+import Control.Monad.Reader hiding (ask)
21+import qualified Control.Monad.Reader as R
22+import Control.Monad.State
23+import qualified Control.Monad.Trans.Reader as R (liftCatch)
24+import qualified Control.Monad.Trans.Writer as W (liftCatch)
25+import Control.Monad.Writer
26+import qualified Data.Aeson as A
27+import Data.Foldable
28+import Data.Functor.Identity
29+import qualified Data.HashMap.Strict.InsOrd as IOHM
30+import Data.List (sortBy)
31+import qualified Data.List as L
32+import qualified Data.List.NonEmpty as NE
33+import qualified Data.Map as M
34+import Data.Maybe
35+import Data.Monoid
36+import Data.OpenApi
37+import Data.OpenApi.Compare.Memo
38+import Data.OpenApi.Compare.References
39+import Data.OpenApi.Compare.Subtree
40+import Data.OpenApi.Compare.Validate.Schema.DNF
41+import Data.OpenApi.Compare.Validate.Schema.JsonFormula
42+import Data.OpenApi.Compare.Validate.Schema.Traced
43+import Data.OpenApi.Compare.Validate.Schema.TypedJson
44+import Data.Ord
45+import qualified Data.Set as S
46+import Data.Text (Text)
47+import qualified Data.Text as T
48+import Data.Traversable (forM)
49+import Text.Pandoc.Builder hiding (Format)
50+
51+data PartitionData
52+ = DByEnumValue (DNF (S.Set A.Value))
53+ | DByProperties (DNF (S.Set Text, S.Set Text)) -- optional, required
54+ deriving stock (Eq, Ord, Show)
55+
56+conjPart :: PartitionData -> PartitionData -> Maybe PartitionData
57+conjPart (DByEnumValue xss) (DByEnumValue yss) = Just . DByEnumValue $ xss /\ yss
58+conjPart (DByProperties xss) (DByProperties yss) = Just . DByProperties $ xss /\ yss
59+conjPart _ _ = Nothing
60+
61+disjPart :: PartitionData -> PartitionData -> Maybe PartitionData
62+disjPart (DByEnumValue xss) (DByEnumValue yss) = Just . DByEnumValue $ xss \/ yss
63+disjPart (DByProperties xss) (DByProperties yss) = Just . DByProperties $ xss \/ yss
64+disjPart _ _ = Nothing
65+
66+newtype Partitions = Partitions (M.Map PartitionLocation (S.Set PartitionData))
67+ deriving stock (Eq, Ord, Show)
68+
69+instance Lattice Partitions where
70+ Partitions xss /\ Partitions yss = Partitions $ M.unionWith conj xss yss
71+ where
72+ conj xs ys = S.fromList . catMaybes $ liftA2 conjPart (S.toList xs) (S.toList ys)
73+ Partitions xss \/ Partitions yss = Partitions $ M.intersectionWith disj xss yss
74+ where
75+ disj xs ys = S.fromList . catMaybes $ liftA2 disjPart (S.toList xs) (S.toList ys)
76+
77+instance BoundedMeetSemiLattice Partitions where
78+ top = Partitions M.empty
79+
80+-- The lattice has no bottom, but we use 'Lifted' to adjoin a free bottom element
81+
82+type PartitionM = ReaderT (Traced (Definitions Schema)) (State (MemoState ()))
83+
84+ignoreKnot :: KnotTier (Lifted Partitions) () PartitionM
85+ignoreKnot =
86+ KnotTier
87+ { onKnotFound = pure ()
88+ , onKnotUsed = \_ -> pure bottom
89+ , tieKnot = \_ -> pure
90+ }
91+
92+singletonPart :: PartitionData -> Lifted Partitions
93+singletonPart = Lift . Partitions . M.singleton PHere . S.singleton
94+
95+partitionSchema :: Traced Schema -> PartitionM (Lifted Partitions)
96+partitionSchema sch = do
97+ allClauses <- case tracedAllOf sch of
98+ Nothing -> pure []
99+ Just xs -> mapM partitionRefSchema xs
100+
101+ anyClause <- case tracedAnyOf sch of
102+ Nothing -> pure top
103+ Just xs -> joins <$> mapM partitionRefSchema xs
104+
105+ oneClause <- case tracedOneOf sch of
106+ Nothing -> pure top
107+ Just xs -> joins <$> mapM partitionRefSchema xs
108+
109+ byEnumClause <- case _schemaEnum $ extract sch of
110+ Nothing -> pure top
111+ Just xs ->
112+ pure . singletonPart $
113+ DByEnumValue $ LiteralDNF (S.fromList xs)
114+
115+ -- We can only partition by presence of a property if additional properties
116+ -- are disallowed, and the property is not optional
117+ let reqd = S.fromList $ _schemaRequired $ extract sch
118+ byPropertiesClause <- case _schemaAdditionalProperties $ extract sch of
119+ Just (AdditionalPropertiesAllowed False) -> do
120+ let props = S.fromList . IOHM.keys . _schemaProperties $ extract sch
121+ pure . singletonPart $
122+ DByProperties $ LiteralDNF (props S.\\ reqd, props `S.intersection` reqd)
123+ _ -> pure top
124+
125+ -- We can partition on something nested in a property only if the property is
126+ -- required
127+ let reqdProps = IOHM.filterWithKey (\k _ -> k `S.member` reqd) $ tracedProperties sch
128+ inPropertiesClauses <- forM (IOHM.toList reqdProps) $ \(k, rs) -> do
129+ f <- partitionRefSchema rs
130+ pure $ fmap (\(Partitions m) -> Partitions $ M.mapKeysMonotonic (PInProperty k) m) f
131+
132+ pure $ meets $ allClauses <> [anyClause, oneClause, byEnumClause, byPropertiesClause] <> inPropertiesClauses
133+
134+partitionRefSchema :: Traced (Referenced Schema) -> PartitionM (Lifted Partitions)
135+partitionRefSchema x = do
136+ defs <- R.ask
137+ memoWithKnot ignoreKnot (partitionSchema $ dereference defs x) (ask x)
138+
139+partitionCondition :: Condition t -> PartitionM (Lifted Partitions)
140+partitionCondition = \case
141+ Exactly x ->
142+ pure . singletonPart $
143+ DByEnumValue $ LiteralDNF (S.singleton $ untypeValue x)
144+ Properties props _ madd -> do
145+ let byProps = case madd of
146+ Just _ -> top
147+ Nothing ->
148+ singletonPart $
149+ DByProperties $
150+ LiteralDNF
151+ ( M.keysSet $ M.filter (not . propRequired) props
152+ , M.keysSet $ M.filter propRequired props
153+ )
154+ inProps <- forM (M.toList $ M.filter propRequired props) $ \(k, prop) -> do
155+ f <- partitionRefSchema $ propRefSchema prop
156+ pure $ fmap (\(Partitions m) -> Partitions $ M.mapKeysMonotonic (PInProperty k) m) f
157+ pure $ byProps /\ meets inProps
158+ _ -> pure top
159+
160+runPartitionM :: Traced (Definitions Schema) -> PartitionM a -> a
161+runPartitionM defs = runIdentity . runMemo () . (`runReaderT` defs)
162+
163+partitionJsonFormulas ::
164+ ProdCons (Traced (Definitions Schema)) ->
165+ ProdCons (JsonFormula t) ->
166+ Lifted Partitions
167+partitionJsonFormulas defs pc = producer pcPart \/ consumer pcPart
168+ where
169+ pcPart = partitionFormula <$> defs <*> pc
170+ partitionFormula def (JsonFormula xss) = runPartitionM def $ forDNF partitionCondition xss
171+
172+selectPartition :: Lifted Partitions -> Maybe (PartitionLocation, S.Set PartitionChoice)
173+selectPartition Bottom = Nothing
174+selectPartition (Lift (Partitions m)) =
175+ go [(loc, part) | (loc, parts) <- sortBy (comparing $ locLength . fst) $ M.toList m, part <- S.toList parts]
176+ where
177+ locLength :: PartitionLocation -> Int
178+ locLength = walk 0
179+ where
180+ walk !n PHere = n
181+ walk !n (PInProperty _ l) = walk (n + 1) l
182+ go [] = Nothing
183+ -- Skip partitioning by property for now
184+ go ((_, DByProperties _) : ps) = go ps
185+ -- Don't partition by enum value at the root (this reports removed enum values as contradictions in their respective partitions)
186+ go ((PHere, DByEnumValue _) : ps) = go ps
187+ go ((loc, DByEnumValue (DNF xss)) : ps)
188+ -- Check that no disjunction branches are unresticted
189+ | Just enums <- traverse (\(Disjunct xs) -> fmap (foldr1 S.intersection) . NE.nonEmpty . S.toList $ xs) . S.toList $ xss =
190+ -- TODO: improve
191+ Just (loc, S.map (CByEnumValue . S.singleton) $ S.unions enums)
192+ | otherwise = go ps
193+
194+-- This essentially has 3 cases:
195+-- Nothing -- we have produced a bottom schema
196+-- Just (False, _) -- there's been no change to the schema
197+-- Just (True, x) -- x is a new schema
198+type IntersectionM = ReaderT (Traced (Definitions Schema)) (WriterT Any Maybe)
199+
200+mBottom :: IntersectionM a
201+mBottom = lift . lift $ Nothing
202+
203+catchBottom :: IntersectionM a -> IntersectionM a -> IntersectionM a
204+catchBottom act handler = R.liftCatch (W.liftCatch (\a h -> a <|> h ())) act (\_ -> handler)
205+
206+mChange :: IntersectionM ()
207+mChange = tell $ Any True
208+
209+data IntersectionResult a = Disjoint | Same a | New a
210+ deriving stock (Eq, Ord, Show)
211+
212+runIntersectionM :: Traced (Definitions Schema) -> IntersectionM a -> IntersectionResult a
213+runIntersectionM defs act = case runWriterT $ runReaderT act defs of
214+ Nothing -> Disjoint
215+ Just (x, Any False) -> Same x
216+ Just (x, Any True) -> New x
217+
218+intersectSchema ::
219+ PartitionLocation ->
220+ PartitionChoice ->
221+ Traced Schema ->
222+ IntersectionM Schema
223+intersectSchema loc part sch = do
224+ allOf' <- forM (tracedAllOf sch) $ \rss ->
225+ -- Assuming i ranges over a nonempty set (checked in processSchema)
226+ -- (⋂_i A[i]) ∩ X = ⋂_i (A[i] ∩ X)
227+ -- If any intersections are empty, the result is empty. If any intersections are a change, the result is a change.
228+ traverse (intersectRefSchema loc part) rss
229+ anyOf' <- forM (tracedAnyOf sch) $ \rss -> do
230+ -- (⋃_i A[i]) ∩ X = ⋃_i (A[i] ∩ X)
231+ -- Collect only the nonempty A[i] ∩ X, unless there are none, in which case the result is empty.
232+ -- If any schema is empty, we remove it from the list which constitutes a change.
233+ mSchemas <- forM rss $ \rs -> catchBottom (Just <$> intersectRefSchema loc part rs) (mChange >> pure Nothing)
234+ case catMaybes mSchemas of
235+ [] -> mBottom
236+ schs -> pure schs
237+ oneOf' <- forM (tracedOneOf sch) $ \rss -> do
238+ -- Same as anyOf'. By intersecting we're only making them more disjoint if anything.
239+ mSchemas <- forM rss $ \rs -> catchBottom (Just <$> intersectRefSchema loc part rs) (mChange >> pure Nothing)
240+ case catMaybes mSchemas of
241+ [] -> mBottom
242+ schs -> pure schs
243+ let sch' = (extract sch) {_schemaAllOf = allOf', _schemaAnyOf = anyOf', _schemaOneOf = oneOf'}
244+ -- Now the local changes:
245+ case loc of
246+ PInProperty k loc' -> case IOHM.lookup k $ tracedProperties sch of
247+ Nothing -> error $ "Partitioning via absent property: " <> T.unpack k
248+ Just prop -> do
249+ prop' <- intersectRefSchema loc' part prop
250+ pure $ sch' {_schemaProperties = IOHM.adjust (const prop') k $ _schemaProperties sch'}
251+ PHere -> case part of
252+ CByEnumValue vals -> do
253+ enum' <- case _schemaEnum sch' of
254+ Nothing -> do
255+ mChange
256+ pure $ S.toList vals
257+ Just xs -> do
258+ when (any (`S.notMember` vals) xs) mChange
259+ case filter (`S.member` vals) xs of
260+ [] -> mBottom
261+ xs' -> pure xs'
262+ pure $ sch' {_schemaEnum = Just enum'}
263+ CByProperties {} -> error "CByProperties not implemented"
264+
265+intersectRefSchema ::
266+ PartitionLocation ->
267+ PartitionChoice ->
268+ Traced (Referenced Schema) ->
269+ IntersectionM (Referenced Schema)
270+intersectRefSchema loc part rs = do
271+ defs <- R.ask
272+ Inline <$> intersectSchema loc part (dereference defs rs)
273+
274+intersectCondition :: Traced (Definitions Schema) -> PartitionLocation -> PartitionChoice -> Condition t -> DNF (Condition t)
275+intersectCondition _defs PHere (CByEnumValue values) cond@(Exactly x) =
276+ if untypeValue x `S.member` values then LiteralDNF cond else bottom
277+intersectCondition defs (PInProperty k loc) part cond@(Properties props add madd) = case M.lookup k props of
278+ Nothing -> LiteralDNF cond -- shouldn't happen
279+ Just prop -> case runIntersectionM defs $ intersectRefSchema loc part $ propRefSchema prop of
280+ New rs' ->
281+ let trs' = traced (ask (propRefSchema prop) >>> step (Partitioned (loc, part))) rs'
282+ in LiteralDNF $ Properties (M.insert k prop {propRefSchema = trs'} props) add madd
283+ Same _ -> LiteralDNF cond
284+ Disjoint -> bottom
285+intersectCondition _defs _loc _part cond = LiteralDNF cond
286+
287+intersectFormula :: Traced (Definitions Schema) -> PartitionLocation -> PartitionChoice -> JsonFormula t -> JsonFormula t
288+intersectFormula defs loc part = JsonFormula . foldDNF (intersectCondition defs loc part) . getJsonFormula
289+
290+tryPartition :: ProdCons (Traced (Definitions Schema)) -> ProdCons (JsonFormula t) -> [(Maybe Partition, ProdCons (JsonFormula t))]
291+tryPartition defs pc = case selectPartition $ partitionJsonFormulas defs pc of
292+ Nothing -> [(Nothing, pc)]
293+ Just (loc, parts) -> [(Just (loc, part), intersectFormula <$> defs <*> pure loc <*> pure part <*> pc) | part <- S.toList parts]
294+
295+showPartition :: Partition -> Inlines
296+showPartition = \case
297+ (partition, CByEnumValue (S.toList -> [v])) ->
298+ renderPartitionLocation partition <> " is " <> showJSONValueInline v
299+ (partition, CByEnumValue (S.toList -> vs)) ->
300+ renderPartitionLocation partition <> " has values: "
301+ <> (fold . L.intersperse ", " . fmap showJSONValueInline $ vs)
302+ (partition, CByProperties (S.toList -> incl) (S.toList -> [])) ->
303+ renderPartitionLocation partition <> " contains the properties: " <> listCodes incl
304+ (partition, CByProperties (S.toList -> []) (S.toList -> excl)) ->
305+ renderPartitionLocation partition <> " does not contain the properties: " <> listCodes excl
306+ (partition, CByProperties (S.toList -> incl) (S.toList -> excl)) ->
307+ renderPartitionLocation partition
308+ <> " contains the properties "
309+ <> listCodes incl
310+ <> " and does not contain the properties "
311+ <> listCodes excl
312+ where
313+ listCodes :: [Text] -> Inlines
314+ listCodes = fold . L.intersperse ", " . fmap code
315+ renderPartitionLocation :: PartitionLocation -> Inlines
316+ renderPartitionLocation p = code $ "$" <> renderPartitionLocation' p
317+ where
318+ renderPartitionLocation' :: PartitionLocation -> Text
319+ renderPartitionLocation' PHere = mempty
320+ renderPartitionLocation' (PInProperty prop rest) = "." <> prop <> renderPartitionLocation' rest
src/Data/OpenApi/Compare/Validate/Schema/Process.hsnew file+375
@@ -0,0 +1,375 @@
1+module Data.OpenApi.Compare.Validate.Schema.Process
2+ ( schemaToFormula,
3+ )
4+where
5+
6+import Algebra.Lattice
7+import Control.Monad.Reader hiding (ask)
8+import qualified Control.Monad.Reader as R
9+import Control.Monad.State
10+import Control.Monad.Writer
11+import qualified Data.Aeson as A
12+import Data.Functor.Identity
13+import qualified Data.HashMap.Strict.InsOrd as IOHM
14+import qualified Data.Map as M
15+import Data.Maybe
16+import Data.Monoid
17+import Data.OpenApi hiding (get)
18+import Data.OpenApi.Compare.Behavior
19+import Data.OpenApi.Compare.Memo
20+import Data.OpenApi.Compare.Paths
21+import qualified Data.OpenApi.Compare.PathsPrefixTree as P
22+import Data.OpenApi.Compare.References
23+import Data.OpenApi.Compare.Subtree
24+import Data.OpenApi.Compare.Validate.Schema.DNF
25+import Data.OpenApi.Compare.Validate.Schema.Issues
26+import Data.OpenApi.Compare.Validate.Schema.JsonFormula
27+import Data.OpenApi.Compare.Validate.Schema.Partition
28+import Data.OpenApi.Compare.Validate.Schema.Traced
29+import Data.OpenApi.Compare.Validate.Schema.TypedJson
30+import Data.Ord
31+import qualified Data.Set as S
32+import Data.Traversable (forM)
33+
34+-- | A fake writer monad that doesn't actually record anything and allows lazy recursion.
35+newtype Silent w a = Silent {runSilent :: a}
36+ deriving stock (Functor)
37+ deriving (Applicative, Monad) via Identity
38+
39+instance Monoid w => MonadWriter w (Silent w) where
40+ tell _ = Silent ()
41+ listen (Silent x) = Silent (x, mempty)
42+ pass (Silent (x, _)) = Silent x
43+
44+type ProcessM = StateT (MemoState ()) (ReaderT (Traced (Definitions Schema)) (Writer (P.PathsPrefixTree Behave AnIssue 'SchemaLevel)))
45+
46+type SilentM = StateT (MemoState ()) (ReaderT (Traced (Definitions Schema)) (Silent (P.PathsPrefixTree Behave AnIssue 'SchemaLevel)))
47+
48+-- Either ProcessM or SilentM
49+type MonadProcess m =
50+ ( MonadReader (Traced (Definitions Schema)) m
51+ , MonadWriter (P.PathsPrefixTree Behave AnIssue 'SchemaLevel) m
52+ , MonadState (MemoState ()) m
53+ )
54+
55+warn :: MonadProcess m => Issue 'SchemaLevel -> m ()
56+warn issue = tell $ P.singleton $ AnItem Root $ anIssue issue
57+
58+-- Perform a computation lazily, ignoring the warnings and discarding memoization/loop detection information.
59+lazily :: MonadProcess m => SilentM a -> m a
60+lazily m = do
61+ defs <- R.ask
62+ pure $ runSilent $ runReaderT (runMemo () m) defs
63+
64+warnKnot :: MonadProcess m => KnotTier (ForeachType JsonFormula) () m
65+warnKnot =
66+ KnotTier
67+ { onKnotFound = warn UnguardedRecursion
68+ , onKnotUsed = \_ -> pure bottom
69+ , tieKnot = \_ -> pure
70+ }
71+
72+processRefSchema ::
73+ MonadProcess m =>
74+ Traced (Referenced Schema) ->
75+ m (ForeachType JsonFormula)
76+processRefSchema x = do
77+ defs <- R.ask
78+ memoWithKnot warnKnot (processSchema $ dereference defs x) (ask x)
79+
80+-- | Turn a schema into a tuple of 'JsonFormula's that describes the condition
81+-- for every possible type of a JSON value. The conditions are independent, and
82+-- are thus checked independently.
83+processSchema ::
84+ MonadProcess m =>
85+ Traced Schema ->
86+ m (ForeachType JsonFormula)
87+processSchema sch@(extract -> Schema {..}) = do
88+ let singletonFormula :: Condition t -> JsonFormula t
89+ singletonFormula = JsonFormula . LiteralDNF
90+
91+ allClauses <- case tracedAllOf sch of
92+ Nothing -> pure []
93+ Just [] -> [] <$ warn (InvalidSchema "no items in allOf")
94+ Just xs -> mapM processRefSchema xs
95+
96+ anyClause <- case tracedAnyOf sch of
97+ Nothing -> pure top
98+ Just [] -> bottom <$ warn (InvalidSchema "no items in anyOf")
99+ Just xs -> joins <$> mapM processRefSchema xs
100+
101+ oneClause <- case tracedOneOf sch of
102+ Nothing -> pure top
103+ Just [] -> bottom <$ warn (InvalidSchema "no items in oneOf")
104+ Just xs -> do
105+ checkOneOfDisjoint xs >>= \case
106+ True -> pure ()
107+ False -> warn OneOfNotDisjoint
108+ joins <$> mapM processRefSchema xs
109+
110+ case _schemaNot of
111+ Nothing -> pure ()
112+ Just _ -> warn (NotSupported "not clause is unsupported")
113+
114+ let typeClause = case _schemaType of
115+ Nothing -> top
116+ Just OpenApiNull ->
117+ bottom
118+ { forNull = top
119+ }
120+ Just OpenApiBoolean ->
121+ bottom
122+ { forBoolean = top
123+ }
124+ Just OpenApiNumber ->
125+ bottom
126+ { forNumber = top
127+ }
128+ Just OpenApiInteger ->
129+ bottom
130+ { forNumber = singletonFormula $ MultipleOf 1
131+ }
132+ Just OpenApiString ->
133+ bottom
134+ { forString = top
135+ }
136+ Just OpenApiArray ->
137+ bottom
138+ { forArray = top
139+ }
140+ Just OpenApiObject ->
141+ bottom
142+ { forObject = top
143+ }
144+
145+ let valueEnum A.Null =
146+ bottom
147+ { forNull = singletonFormula $ Exactly TNull
148+ }
149+ valueEnum (A.Bool b) =
150+ bottom
151+ { forBoolean = singletonFormula $ Exactly $ TBool b
152+ }
153+ valueEnum (A.Number n) =
154+ bottom
155+ { forNumber = singletonFormula $ Exactly $ TNumber n
156+ }
157+ valueEnum (A.String s) =
158+ bottom
159+ { forString = singletonFormula $ Exactly $ TString s
160+ }
161+ valueEnum (A.Array a) =
162+ bottom
163+ { forArray = singletonFormula $ Exactly $ TArray a
164+ }
165+ valueEnum (A.Object o) =
166+ bottom
167+ { forObject = singletonFormula $ Exactly $ TObject o
168+ }
169+ enumClause <- case _schemaEnum of
170+ Nothing -> pure top
171+ Just [] -> bottom <$ warn (InvalidSchema "no items in enum")
172+ Just xs -> pure $ joins (valueEnum <$> xs)
173+
174+ let maximumClause = case _schemaMaximum of
175+ Nothing -> top
176+ Just n ->
177+ top
178+ { forNumber = singletonFormula $
179+ Maximum $
180+ case _schemaExclusiveMaximum of
181+ Just True -> Exclusive n
182+ _ -> Inclusive n
183+ }
184+
185+ minimumClause = case _schemaMinimum of
186+ Nothing -> top
187+ Just n ->
188+ top
189+ { forNumber = singletonFormula $
190+ Minimum $
191+ Down $
192+ case _schemaExclusiveMinimum of
193+ Just True -> Exclusive $ Down n
194+ _ -> Inclusive $ Down n
195+ }
196+
197+ multipleOfClause = case _schemaMultipleOf of
198+ Nothing -> top
199+ Just n ->
200+ top
201+ { forNumber = singletonFormula $ MultipleOf n
202+ }
203+
204+ formatClause <- case _schemaFormat of
205+ Nothing -> pure top
206+ Just f
207+ | f `elem` ["int32", "int64", "float", "double"] ->
208+ pure
209+ top
210+ { forNumber = singletonFormula $ NumberFormat f
211+ }
212+ Just f
213+ | f `elem` ["byte", "binary", "date", "date-time", "password", "uuid"] ->
214+ pure
215+ top
216+ { forString = singletonFormula $ StringFormat f
217+ }
218+ Just f -> top <$ warn (NotSupported $ "Unknown format: " <> f)
219+
220+ let maxLengthClause = case _schemaMaxLength of
221+ Nothing -> top
222+ Just n ->
223+ top
224+ { forString = singletonFormula $ MaxLength n
225+ }
226+
227+ minLengthClause = case _schemaMinLength of
228+ Nothing -> top
229+ Just n ->
230+ top
231+ { forString = singletonFormula $ MinLength n
232+ }
233+
234+ patternClause = case _schemaPattern of
235+ Nothing -> top
236+ Just p ->
237+ top
238+ { forString = singletonFormula $ Pattern p
239+ }
240+
241+ itemsClause <- case tracedItems sch of
242+ Nothing -> pure top
243+ Just (Left rs) -> do
244+ f <- lazily $ processRefSchema rs
245+ pure top {forArray = singletonFormula $ Items f rs}
246+ Just (Right rss) -> do
247+ fsrs <- forM rss $ \rs -> do
248+ f <- lazily $ processRefSchema rs
249+ pure (f, rs)
250+ pure top {forArray = singletonFormula $ TupleItems fsrs}
251+
252+ let maxItemsClause = case _schemaMaxItems of
253+ Nothing -> top
254+ Just n ->
255+ top
256+ { forArray = singletonFormula $ MaxItems n
257+ }
258+
259+ minItemsClause = case _schemaMinItems of
260+ Nothing -> top
261+ Just n ->
262+ top
263+ { forArray = singletonFormula $ MinItems n
264+ }
265+
266+ uniqueItemsClause = case _schemaUniqueItems of
267+ Just True ->
268+ top
269+ { forArray = singletonFormula UniqueItems
270+ }
271+ _ -> top
272+
273+ (addProps, addPropSchema) <- case tracedAdditionalProperties sch of
274+ Just (Right rs) -> (,Just rs) <$> lazily (processRefSchema rs)
275+ Just (Left False) -> pure (bottom, Nothing)
276+ _ -> pure (top, Just $ traced (ask sch `Snoc` AdditionalPropertiesStep) $ Inline mempty)
277+ propList <- forM (S.toList . S.fromList $ IOHM.keys _schemaProperties <> _schemaRequired) $ \k -> do
278+ (f, psch) <- case IOHM.lookup k $ tracedProperties sch of
279+ Just rs -> (,rs) <$> lazily (processRefSchema rs)
280+ Nothing ->
281+ let fakeSchema = traced (ask sch `Snoc` AdditionalPropertiesStep) $ Inline mempty
282+ in -- The mempty here is incorrect, but if addPropSchema was Nothing, then
283+ -- addProps is bottom, and k is in _schemaRequired. We handle this situation
284+ -- below and short-circuit the entire Properties condition to bottom
285+ pure (addProps, fromMaybe fakeSchema addPropSchema)
286+ pure (k, Property (k `elem` _schemaRequired) f psch)
287+ let allBottom f = getAll $
288+ foldType $ \_ ty -> case getJsonFormula $ ty f of
289+ BottomDNF -> All True
290+ _ -> All False
291+ allTop f = getAll $
292+ foldType $ \_ ty -> case getJsonFormula $ ty f of
293+ TopDNF -> All True
294+ _ -> All False
295+ -- remove optional fields whose schemata match that of additional props
296+ propMap = M.filter (\p -> propRequired p || propFormula p /= addProps) $ M.fromList propList
297+ propertiesClause
298+ | any (\p -> propRequired p && allBottom (propFormula p)) propMap =
299+ bottom -- if any required field has unsatisfiable schema
300+ | M.null propMap
301+ , allTop addProps =
302+ top -- if all fields are optional and have trivial schemata
303+ | otherwise =
304+ top
305+ { forObject = singletonFormula $ Properties propMap addProps addPropSchema
306+ }
307+
308+ maxPropertiesClause = case _schemaMaxProperties of
309+ Nothing -> top
310+ Just n ->
311+ top
312+ { forObject = singletonFormula $ MaxProperties n
313+ }
314+
315+ minPropertiesClause = case _schemaMinProperties of
316+ Nothing -> top
317+ Just n ->
318+ top
319+ { forObject = singletonFormula $ MinProperties n
320+ }
321+
322+ nullableClause
323+ | Just True <- _schemaNullable =
324+ bottom
325+ { forNull = singletonFormula $ Exactly TNull
326+ }
327+ | otherwise = bottom
328+
329+ pure $
330+ nullableClause
331+ \/ meets
332+ ( allClauses
333+ <> [ anyClause
334+ , oneClause
335+ , typeClause
336+ , enumClause
337+ , maximumClause
338+ , minimumClause
339+ , multipleOfClause
340+ , formatClause
341+ , maxLengthClause
342+ , minLengthClause
343+ , patternClause
344+ , itemsClause
345+ , maxItemsClause
346+ , minItemsClause
347+ , uniqueItemsClause
348+ , propertiesClause
349+ , maxPropertiesClause
350+ , minPropertiesClause
351+ ]
352+ )
353+
354+{- TODO: ReadOnly/WriteOnly #68 -}
355+
356+checkOneOfDisjoint :: MonadProcess m => [Traced (Referenced Schema)] -> m Bool
357+checkOneOfDisjoint schs = do
358+ defs <- R.ask
359+ pure $ case selectPartition $ joins $ runPartitionM defs $ traverse partitionRefSchema schs of
360+ Nothing -> False
361+ Just (loc, parts) ->
362+ let intersects part sch = case runIntersectionM defs $ intersectRefSchema loc part sch of
363+ Disjoint -> False
364+ _ -> True
365+ in all (\part -> 1 >= length (filter (intersects part) schs)) parts
366+ where
367+
368+runProcessM :: Traced (Definitions Schema) -> ProcessM a -> (a, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
369+runProcessM defs = runWriter . (`runReaderT` defs) . runMemo ()
370+
371+schemaToFormula ::
372+ Traced (Definitions Schema) ->
373+ Traced Schema ->
374+ (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
375+schemaToFormula defs rs = runProcessM defs $ processSchema rs
src/Data/OpenApi/Compare/Validate/Schema/Traced.hsnew file+115
@@ -0,0 +1,115 @@
1+{-# OPTIONS_GHC -Wno-orphans #-}
2+
3+module Data.OpenApi.Compare.Validate.Schema.Traced
4+ ( Step (..),
5+ tracedAllOf,
6+ tracedAnyOf,
7+ tracedOneOf,
8+ tracedItems,
9+ tracedAdditionalProperties,
10+ tracedDiscriminator,
11+ tracedProperties,
12+ tracedConjunct,
13+ PartitionLocation (..),
14+ PartitionChoice (..),
15+ Partition,
16+ )
17+where
18+
19+import qualified Data.Aeson as A
20+import Data.Functor
21+import qualified Data.HashMap.Strict.InsOrd as IOHM
22+import qualified Data.List.NonEmpty as NE
23+import Data.OpenApi
24+import Data.OpenApi.Compare.Subtree
25+import qualified Data.Set as S
26+import Data.Text (Text)
27+
28+data PartitionChoice
29+ = CByEnumValue (S.Set A.Value)
30+ | CByProperties (S.Set Text) (S.Set Text) -- included, excluded
31+ deriving stock (Eq, Ord, Show)
32+
33+data PartitionLocation
34+ = PHere
35+ | PInProperty Text PartitionLocation
36+ deriving stock (Eq, Ord, Show)
37+
38+type Partition = (PartitionLocation, PartitionChoice)
39+
40+instance Steppable Schema (Referenced Schema) where
41+ data Step Schema (Referenced Schema)
42+ = AllOfStep Int
43+ | OneOfStep Int
44+ | AnyOfStep Int
45+ | ItemsObjectStep
46+ | ItemsArrayStep Int
47+ | AdditionalPropertiesStep
48+ | NotStep
49+ | ImplicitTopSchema
50+ deriving stock (Eq, Ord, Show)
51+
52+instance Steppable (Referenced Schema) (Referenced Schema) where
53+ data Step (Referenced Schema) (Referenced Schema)
54+ = -- | Invariant (for better memoization only): the "tail" of the trace is
55+ -- the "least" of the traces of the conjuncted schemata
56+ ConjunctedWith (NE.NonEmpty (Trace (Referenced Schema)))
57+ | Partitioned Partition
58+ deriving stock (Eq, Ord, Show)
59+
60+instance Steppable Schema (Definitions (Referenced Schema)) where
61+ data Step Schema (Definitions (Referenced Schema)) = PropertiesStep
62+ deriving stock (Eq, Ord, Show)
63+
64+instance Steppable Schema Discriminator where
65+ data Step Schema Discriminator = DiscriminatorStep
66+ deriving stock (Eq, Ord, Show)
67+
68+instance Steppable Discriminator (Definitions (Referenced Schema)) where
69+ data Step Discriminator (Definitions (Referenced Schema)) = DiscriminatorMapping
70+ deriving stock (Eq, Ord, Show)
71+
72+tracedAllOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
73+tracedAllOf sch =
74+ _schemaAllOf (extract sch) <&> \xs ->
75+ [traced (ask sch >>> step (AllOfStep i)) x | (i, x) <- zip [0 ..] xs]
76+
77+tracedAnyOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
78+tracedAnyOf sch =
79+ _schemaAnyOf (extract sch) <&> \xs ->
80+ [traced (ask sch >>> step (AnyOfStep i)) x | (i, x) <- zip [0 ..] xs]
81+
82+tracedOneOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
83+tracedOneOf sch =
84+ _schemaOneOf (extract sch) <&> \xs ->
85+ [traced (ask sch >>> step (OneOfStep i)) x | (i, x) <- zip [0 ..] xs]
86+
87+tracedItems :: Traced Schema -> Maybe (Either (Traced (Referenced Schema)) [Traced (Referenced Schema)])
88+tracedItems sch =
89+ _schemaItems (extract sch) <&> \case
90+ OpenApiItemsObject x -> Left $ traced (ask sch >>> step ItemsObjectStep) x
91+ OpenApiItemsArray xs ->
92+ Right
93+ [traced (ask sch >>> step (ItemsArrayStep i)) x | (i, x) <- zip [0 ..] xs]
94+
95+tracedAdditionalProperties :: Traced Schema -> Maybe (Either Bool (Traced (Referenced Schema)))
96+tracedAdditionalProperties sch =
97+ _schemaAdditionalProperties (extract sch) <&> \case
98+ AdditionalPropertiesAllowed b -> Left b
99+ AdditionalPropertiesSchema x -> Right $ traced (ask sch >>> step AdditionalPropertiesStep) x
100+
101+tracedDiscriminator :: Traced Schema -> Maybe (Traced Discriminator)
102+tracedDiscriminator = sequence . stepTraced DiscriminatorStep . fmap _schemaDiscriminator
103+
104+tracedProperties :: Traced Schema -> IOHM.InsOrdHashMap Text (Traced (Referenced Schema))
105+tracedProperties sch =
106+ IOHM.mapWithKey
107+ (\k -> traced (ask sch >>> step PropertiesStep >>> step (InsOrdHashMapKeyStep k)))
108+ (_schemaProperties $ extract sch)
109+
110+tracedConjunct :: NE.NonEmpty (Traced (Referenced Schema)) -> Traced (Referenced Schema)
111+tracedConjunct refSchemas = case NE.sortWith ask refSchemas of
112+ (rs NE.:| []) -> rs
113+ (rs1 NE.:| rs2 : rss) ->
114+ traced (ask rs1 >>> step (ConjunctedWith $ ask <$> rs2 NE.:| rss)) $
115+ Inline mempty {_schemaAllOf = Just $ extract <$> rs1 : rs2 : rss}
src/Data/OpenApi/Compare/Validate/Schema/TypedJson.hsnew file+120
@@ -0,0 +1,120 @@
1+module Data.OpenApi.Compare.Validate.Schema.TypedJson
2+ ( JsonType (..),
3+ describeJSONType,
4+ TypedValue (..),
5+ untypeValue,
6+ ForeachType (..),
7+ foldType,
8+ forType_,
9+ )
10+where
11+
12+import Algebra.Lattice
13+import qualified Data.Aeson as A
14+import Data.Kind
15+import Data.Monoid
16+import Data.Scientific
17+import Data.String
18+import Data.Text (Text)
19+import Data.Typeable
20+
21+-- | Type of a JSON value
22+data JsonType
23+ = Null
24+ | Boolean
25+ | Number
26+ | String
27+ | Array
28+ | Object
29+ deriving stock (Eq, Ord, Show)
30+
31+describeJSONType :: IsString s => JsonType -> s
32+describeJSONType = \case
33+ Null -> "Null"
34+ Boolean -> "Boolean"
35+ Number -> "Number"
36+ String -> "String"
37+ Array -> "Array"
38+ Object -> "Object"
39+
40+-- | A 'A.Value' whose type we know
41+data TypedValue :: JsonType -> Type where
42+ TNull :: TypedValue 'Null
43+ TBool :: !Bool -> TypedValue 'Boolean
44+ TNumber :: !Scientific -> TypedValue 'Number
45+ TString :: !Text -> TypedValue 'String
46+ TArray :: !A.Array -> TypedValue 'Array
47+ TObject :: !A.Object -> TypedValue 'Object
48+
49+deriving stock instance Eq (TypedValue t)
50+
51+deriving stock instance Ord (TypedValue t)
52+
53+deriving stock instance Show (TypedValue t)
54+
55+untypeValue :: TypedValue t -> A.Value
56+untypeValue TNull = A.Null
57+untypeValue (TBool b) = A.Bool b
58+untypeValue (TNumber n) = A.Number n
59+untypeValue (TString s) = A.String s
60+untypeValue (TArray a) = A.Array a
61+untypeValue (TObject o) = A.Object o
62+
63+data ForeachType (f :: JsonType -> Type) = ForeachType
64+ { forNull :: f 'Null
65+ , forBoolean :: f 'Boolean
66+ , forNumber :: f 'Number
67+ , forString :: f 'String
68+ , forArray :: f 'Array
69+ , forObject :: f 'Object
70+ }
71+
72+deriving stock instance (forall x. Typeable x => Eq (f x)) => Eq (ForeachType f)
73+
74+deriving stock instance (forall x. Typeable x => Ord (f x)) => Ord (ForeachType f)
75+
76+deriving stock instance (forall x. Typeable x => Show (f x)) => Show (ForeachType f)
77+
78+foldType :: Monoid m => (forall x. Typeable x => JsonType -> (ForeachType f -> f x) -> m) -> m
79+foldType k =
80+ k Null forNull
81+ <> k Boolean forBoolean
82+ <> k Number forNumber
83+ <> k String forString
84+ <> k Array forArray
85+ <> k Object forObject
86+
87+forType_ :: Applicative m => (forall x. Typeable x => JsonType -> (ForeachType f -> f x) -> m ()) -> m ()
88+forType_ k = getAp $ foldType (\ty proj -> Ap $ k ty proj)
89+
90+broadcastType :: (forall x. Typeable x => f x) -> ForeachType f
91+broadcastType k =
92+ ForeachType
93+ { forNull = k
94+ , forBoolean = k
95+ , forNumber = k
96+ , forString = k
97+ , forArray = k
98+ , forObject = k
99+ }
100+
101+zipType :: (forall x. Typeable x => f x -> g x -> h x) -> ForeachType f -> ForeachType g -> ForeachType h
102+zipType k f1 f2 =
103+ ForeachType
104+ { forNull = k (forNull f1) (forNull f2)
105+ , forBoolean = k (forBoolean f1) (forBoolean f2)
106+ , forNumber = k (forNumber f1) (forNumber f2)
107+ , forString = k (forString f1) (forString f2)
108+ , forArray = k (forArray f1) (forArray f2)
109+ , forObject = k (forObject f1) (forObject f2)
110+ }
111+
112+instance (forall x. Lattice (f x)) => Lattice (ForeachType f) where
113+ (\/) = zipType (\/)
114+ (/\) = zipType (/\)
115+
116+instance (forall x. BoundedJoinSemiLattice (f x)) => BoundedJoinSemiLattice (ForeachType f) where
117+ bottom = broadcastType bottom
118+
119+instance (forall x. BoundedMeetSemiLattice (f x)) => BoundedMeetSemiLattice (ForeachType f) where
120+ top = broadcastType top
src/OpenAPI/Checker/Validate/SecurityRequirement.hs → src/Data/OpenApi/Compare/Validate/SecurityRequirement.hsrenamed+15−14
@@ -1,8 +1,8 @@
11{-# LANGUAGE PartialTypeSignatures #-}
22{-# OPTIONS_GHC -Wno-orphans #-}
33
4−module OpenAPI.Checker.Validate.SecurityRequirement
5− ( Issue (..)
4+module Data.OpenApi.Compare.Validate.SecurityRequirement
5+ ( Issue (..),
66 )
77where
88
@@ -17,14 +17,14 @@ import Data.HList
1717import qualified Data.HashMap.Strict.InsOrd as IOHM
1818import qualified Data.List.NonEmpty as NE
1919import Data.OpenApi
20+import Data.OpenApi.Compare.Behavior
21+import Data.OpenApi.Compare.Subtree
22+import Data.OpenApi.Compare.Validate.OAuth2Flows
23+import Data.OpenApi.Compare.Validate.SecurityScheme ()
2024import Data.Set (Set)
2125import qualified Data.Set as S
2226import Data.Text (Text)
2327import Data.Traversable
24−import OpenAPI.Checker.Behavior
25−import OpenAPI.Checker.Subtree
26−import OpenAPI.Checker.Validate.OAuth2Flows
27−import OpenAPI.Checker.Validate.SecurityScheme ()
2828
2929instance Subtree SecurityRequirement where
3030 type SubtreeLevel SecurityRequirement = 'SecurityRequirementLevel
@@ -41,18 +41,19 @@ instance Subtree SecurityRequirement where
4141 for (IOHM.toList $ getSecurityRequirement sec) $ \(key, scopes) ->
4242 (,scopes) <$> lookupScheme key defs
4343 structuralMaybeWith
44− (\pc' -> do
45− let ProdCons pScopes cScopes = fmap snd <$> pc'
46− unless (pScopes == cScopes) structuralIssue
47− structuralList env $ fmap fst <$> pc'
48− pure ())
44+ ( \pc' -> do
45+ let ProdCons pScopes cScopes = fmap snd <$> pc'
46+ unless (pScopes == cScopes) structuralIssue
47+ structuralList env $ fmap fst <$> pc'
48+ pure ()
49+ )
4950 normalized
5051 pure ()
5152 checkSemanticCompatibility env bhv' pc = do
5253 let schemes = getH @(ProdCons (Traced (Definitions SecurityScheme))) env
5354 ( ProdCons pErrs cErrs
54− , (ProdCons pSchemes cSchemes)
55− :: ProdCons [(Behavior 'SecuritySchemeLevel, Traced SecurityScheme, [Text])]
55+ , (ProdCons pSchemes cSchemes) ::
56+ ProdCons [(Behavior 'SecuritySchemeLevel, Traced SecurityScheme, [Text])]
5657 ) =
5758 NE.unzip $
5859 partitionEithers <$> do
@@ -102,7 +103,7 @@ instance Subtree SecurityRequirement where
102103 (SecuritySchemeOAuth2 {}, SecuritySchemeOAuth2 {}) -> pure ()
103104 _ -> unless (null pScopes && null cScopes) $ issueAt bhv CanNotHaveScopes
104105 for_ errs $ issueAt bhv
105− checkCompatibility env bhv pc'
106+ checkCompatibility bhv env pc'
106107 pure ()
107108 pure ()
108109
src/OpenAPI/Checker/Validate/SecurityScheme.hs → src/Data/OpenApi/Compare/Validate/SecurityScheme.hsrenamed+8−8
@@ -1,16 +1,16 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.Validate.SecurityScheme
3+module Data.OpenApi.Compare.Validate.SecurityScheme
44 (
55 )
66where
77
88import Control.Monad
99import Data.OpenApi
10−import OpenAPI.Checker.Behavior
11−import OpenAPI.Checker.Orphans ()
12−import OpenAPI.Checker.Subtree
13−import OpenAPI.Checker.Validate.OAuth2Flows
10+import Data.OpenApi.Compare.Behavior
11+import Data.OpenApi.Compare.Orphans ()
12+import Data.OpenApi.Compare.Subtree
13+import Data.OpenApi.Compare.Validate.OAuth2Flows
1414
1515instance Subtree SecurityScheme where
1616 type CheckEnv SecurityScheme = '[]
@@ -26,7 +26,7 @@ instance Subtree SecurityScheme where
2626 (ProdCons (Traced _ (SecuritySchemeApiKey pParams)) (Traced _ (SecuritySchemeApiKey cParams))) -> do
2727 unless (pParams == cParams) (issueAt bhv $ ApiKeyParamsDontMatch pParams cParams)
2828 (ProdCons (Traced pT (SecuritySchemeOAuth2 pFlows)) (Traced cT (SecuritySchemeOAuth2 cFlows))) -> do
29− checkCompatibility env bhv . fmap (stepTraced SecurityOAuthFlowsStep) $ ProdCons (Traced pT pFlows) (Traced cT cFlows)
29+ checkCompatibility bhv env . fmap (stepTraced SecurityOAuthFlowsStep) $ ProdCons (Traced pT pFlows) (Traced cT cFlows)
3030 (ProdCons (Traced _ (SecuritySchemeOpenIdConnect pUrl)) (Traced _ (SecuritySchemeOpenIdConnect cUrl))) -> do
3131 unless (pUrl == cUrl) (issueAt bhv $ OpenIdConnectUrlsDontMatch pUrl cUrl)
3232 _ -> issueAt bhv DifferentSecuritySchemes
@@ -36,8 +36,8 @@ tracedSecuritySchemaTypes (Traced t x) = Traced (t >>> step SecuritySchemeTypeSt
3636
3737instance Steppable SecurityScheme SecuritySchemeType where
3838 data Step SecurityScheme SecuritySchemeType = SecuritySchemeTypeStep
39− deriving (Eq, Ord, Show)
39+ deriving stock (Eq, Ord, Show)
4040
4141instance Steppable SecuritySchemeType OAuth2Flows where
4242 data Step SecuritySchemeType OAuth2Flows = SecurityOAuthFlowsStep
43− deriving (Eq, Ord, Show)
43+ deriving stock (Eq, Ord, Show)
src/OpenAPI/Checker/Validate/Server.hs → src/Data/OpenApi/Compare/Validate/Server.hsrenamed+34−26
@@ -1,7 +1,7 @@
11{-# OPTIONS_GHC -Wno-orphans #-}
22
3−module OpenAPI.Checker.Validate.Server
4− ( Issue (..)
3+module Data.OpenApi.Compare.Validate.Server
4+ ( Issue (..),
55 )
66where
77
@@ -19,21 +19,21 @@ import qualified Data.HashSet.InsOrd as IOHM
1919import qualified Data.HashSet.InsOrd as IOHS
2020import Data.Maybe
2121import Data.OpenApi
22+import Data.OpenApi.Compare.Behavior
23+import Data.OpenApi.Compare.Common
24+import Data.OpenApi.Compare.Paths
25+import Data.OpenApi.Compare.Subtree
26+import Data.OpenApi.Compare.Validate.MediaTypeObject
2227import qualified Data.Set as S
2328import Data.Text (Text)
2429import qualified Data.Text as T
2530import Data.Traversable
26−import OpenAPI.Checker.Behavior
27−import OpenAPI.Checker.Common
28−import OpenAPI.Checker.Paths
29−import OpenAPI.Checker.Subtree
30−import OpenAPI.Checker.Validate.MediaTypeObject
3131import Text.Pandoc.Builder
3232import Prelude as P
3333
34−tracedParsedServerUrlParts
35− :: Server
36− -> Either (Issue 'ServerLevel) ProcessedServer
34+tracedParsedServerUrlParts ::
35+ Server ->
36+ Either (Issue 'ServerLevel) ProcessedServer
3737tracedParsedServerUrlParts s =
3838 let parsedUrl = parseServerUrl $ _serverUrl s
3939 lookupVar var = case IOHM.lookup var (_serverVariables s) of
@@ -46,7 +46,7 @@ instance Behavable 'OperationLevel 'ServerLevel where
4646 = InServer Text
4747 deriving stock (Eq, Ord, Show)
4848
49− describeBehaviour (InServer n) = "Server " <> code n
49+ describeBehavior (InServer n) = "Server " <> code n
5050
5151instance Subtree [Server] where
5252 type SubtreeLevel [Server] = 'OperationLevel
@@ -63,11 +63,12 @@ instance Subtree [Server] where
6363 pcServer
6464 <&> partitionEithers
6565 . fmap
66− (\(Traced t s) ->
67− let bhv = beh >>> step (InServer $ _serverUrl s)
68− in case tracedParsedServerUrlParts s of
69− Left e -> Left $ issueAt bhv e
70− Right u -> Right (bhv, Traced (t >>> step (ServerStep $ _serverUrl s)) u))
66+ ( \(Traced t s) ->
67+ let bhv = beh >>> step (InServer $ _serverUrl s)
68+ in case tracedParsedServerUrlParts s of
69+ Left e -> Left $ issueAt bhv e
70+ Right u -> Right (bhv, Traced (t >>> step (ServerStep $ _serverUrl s)) u)
71+ )
7172 . sequence
7273 sequenceA_ pErrs
7374 sequenceA_ cErrs
@@ -76,7 +77,7 @@ instance Subtree [Server] where
7677 anyOfAt
7778 bhv
7879 ServerNotMatched
79− [ checkCompatibility env bhv (ProdCons pUrl cUrl)
80+ [ checkCompatibility bhv env (ProdCons pUrl cUrl)
8081 | cUrl <- potentiallyCompatible
8182 ]
8283 pure ()
@@ -101,7 +102,7 @@ data ServerUrlPart var
101102 deriving stock (Eq, Show, Functor, Foldable, Traversable)
102103
103104-- | This is super rough. Things like @{a|b}c@ will not match @ac@.
104−-- FIXME: https://github.com/typeable/openapi-diff/issues/46
105+-- FIXME: #46
105106--
106107-- NOTE: syntax is defined vaguely in the spec.
107108parseServerUrl :: Text -> [ServerUrlPart Text]
@@ -124,7 +125,7 @@ parseServerUrl = fromRight undefined . parseOnly (serverUrlParser <* endOfInput)
124125
125126instance Steppable [Server] ProcessedServer where
126127 data Step [Server] ProcessedServer = ServerStep Text
127− deriving (Eq, Ord, Show)
128+ deriving stock (Eq, Ord, Show)
128129
129130instance Issuable 'ServerLevel where
130131 data Issue 'ServerLevel
@@ -133,14 +134,21 @@ instance Issuable 'ServerLevel where
133134 | ServerVariableNotDefined Text
134135 | ServerNotMatched
135136 deriving stock (Eq, Ord, Show)
136− issueIsUnsupported _ = False
137− describeIssue (EnumValueNotConsumed _ v) =
138− para $ "Enum value " <> code v <> " is not supported."
139− describeIssue (ConsumerNotOpen _) =
140− para $ "Expected a variable to be open (any value), but it wasn't."
141− describeIssue (ServerVariableNotDefined k) =
137+ issueKind = \case
138+ ServerVariableNotDefined _ -> SchemaInvalid
139+ _ -> CertainIssue
140+ describeIssue Forward (EnumValueNotConsumed _ v) =
141+ para $ "Enum value " <> code v <> " has been removed."
142+ describeIssue Backward (EnumValueNotConsumed _ v) =
143+ para $ "Enum value " <> code v <> " has been added."
144+ describeIssue Forward (ConsumerNotOpen _) =
145+ para $ "A variable has been changed from being open to being closed."
146+ describeIssue Backward (ConsumerNotOpen _) =
147+ para $ "A variable has been changed from being closed to being open."
148+ describeIssue _ (ServerVariableNotDefined k) =
142149 para $ "Variable " <> code k <> " is not defined."
143− describeIssue ServerNotMatched = para $ "Couldn't find a matching server."
150+ describeIssue Forward ServerNotMatched = para $ "The server was removed."
151+ describeIssue Backward ServerNotMatched = para $ "The server was added."
144152
145153instance Subtree ProcessedServer where
146154 type SubtreeLevel ProcessedServer = 'ServerLevel
src/Data/OpenApi/Compare/Validate/Sums.hsnew file+25
@@ -0,0 +1,25 @@
1+module Data.OpenApi.Compare.Validate.Sums
2+ ( checkSums,
3+ )
4+where
5+
6+import Data.Foldable
7+import Data.Map.Strict (Map)
8+import qualified Data.Map.Strict as M
9+import Data.OpenApi.Compare.Behavior
10+import Data.OpenApi.Compare.Paths
11+import Data.OpenApi.Compare.Subtree
12+
13+checkSums ::
14+ (Ord k, Issuable l) =>
15+ Paths q r l ->
16+ (k -> Issue l) ->
17+ (k -> ProdCons t -> CompatFormula' q AnIssue r ()) ->
18+ ProdCons (Map k t) ->
19+ CompatFormula' q AnIssue r ()
20+checkSums xs noElt check (ProdCons p c) = for_ (M.toList p) $ \(key, prodElt) ->
21+ case M.lookup key c of
22+ Nothing -> issueAt xs $ noElt key
23+ Just consElt ->
24+ let sumElts = ProdCons prodElt consElt
25+ in check key sumElts
src/Data/OpenUnion/Extra.hsnew file+43
@@ -0,0 +1,43 @@
1+module Data.OpenUnion.Extra
2+ ( (@@>),
3+ TryLiftUnion (..),
4+ pattern SingletonUnion,
5+ )
6+where
7+
8+import Control.Applicative
9+import Data.Dynamic
10+import Data.OpenUnion.Internal
11+import Data.Typeable
12+import TypeFun.Data.List hiding (Union)
13+
14+class TryLiftUnion xs where
15+ tryLiftUnion :: (Alternative m, Typeable x) => x -> m (Union xs)
16+
17+instance TryLiftUnion '[] where
18+ tryLiftUnion _ = empty
19+
20+instance
21+ (Typeable y, SubList ys (y : ys), TryLiftUnion ys) =>
22+ TryLiftUnion (y ': ys)
23+ where
24+ tryLiftUnion (x :: x) = case eqT @x @y of
25+ Nothing -> reUnion <$> tryLiftUnion @ys x
26+ Just Refl -> pure $ liftUnion x
27+
28+-- | Like '@>', but enforces a specific type list order.
29+-- (Useful for deconstruction-directed type inference.)
30+(@@>) :: Typeable a => (a -> b) -> (Union xs -> b) -> Union (a ': xs) -> b
31+r @@> l = either l r . restrict'
32+ where
33+ restrict' :: Typeable a => Union (a ': aa) -> Either (Union aa) a
34+ restrict' (Union d) = maybe (Left $ Union d) Right $ fromDynamic d
35+{-# INLINE (@@>) #-}
36+
37+infixr 2 @@>
38+
39+pattern SingletonUnion :: (Typeable a, Elem a s) => a -> Union s
40+pattern SingletonUnion x <-
41+ ((\(Union y) -> fromDynamic y) -> Just x)
42+ where
43+ SingletonUnion x = liftUnion x
src/OpenAPI/Checker/Behavior.hsdeleted−63
@@ -1,63 +0,0 @@
1−module OpenAPI.Checker.Behavior
2− ( BehaviorLevel (..)
3− , Behavable (..)
4− , Issuable (..)
5− , Behavior
6− , AnIssue (..)
7− )
8−where
9−
10−import Data.Aeson
11−import Data.Kind
12−import Data.Typeable
13−import OpenAPI.Checker.Paths
14−import Text.Pandoc.Builder
15−
16−-- | Kind
17−data BehaviorLevel
18− = APILevel
19− | ServerLevel
20− | SecurityRequirementLevel
21− | SecuritySchemeLevel
22− | PathLevel
23− | OperationLevel
24− | PathFragmentLevel
25− | RequestLevel
26− | ResponseLevel
27− | HeaderLevel
28− | -- | either request or response data
29− PayloadLevel
30− | SchemaLevel
31− | TypedSchemaLevel
32− | LinkLevel
33− | CallbackLevel
34−
35−class
36− (Ord (Behave a b), Show (Behave a b)) =>
37− Behavable (a :: BehaviorLevel) (b :: BehaviorLevel)
38− where
39− data Behave a b
40− describeBehaviour :: Behave a b -> Inlines
41−
42−type instance AdditionalQuiverConstraints Behave a b = Behavable a b
43−
44−class (Typeable l, Ord (Issue l), Show (Issue l)) => Issuable (l :: BehaviorLevel) where
45− data Issue l :: Type
46− describeIssue :: Issue l -> Blocks
47− issueIsUnsupported :: Issue l -> Bool
48−
49−-- | A set of interactions having common unifying features
50−type Behavior = Paths Behave 'APILevel
51−
52−instance Issuable l => ToJSON (Issue l) where
53− toJSON = toJSON . show
54−
55−data AnIssue (l :: BehaviorLevel) where
56− AnIssue :: Issuable l => Issue l -> AnIssue l
57−
58−deriving stock instance Eq (AnIssue l)
59−
60−deriving stock instance Ord (AnIssue l)
61−
62−instance ToJSON (AnIssue l) where
63− toJSON (AnIssue issue) = toJSON issue
src/OpenAPI/Checker/Memo.hsdeleted−126
@@ -1,126 +0,0 @@
1−{-# LANGUAGE AllowAmbiguousTypes #-}
2−-- | Utilities for effectfully memoizing other, more effectful functions.
3−module OpenAPI.Checker.Memo
4− ( MonadMemo
5− , MemoState
6− , runMemo
7− , modifyMemoNonce
8− , KnotTier(..)
9− , unknot
10− , memoWithKnot
11− , memoTaggedWithKnot
12− ) where
13−
14−import Control.Monad.State
15−import Data.Dynamic
16−import qualified Data.Map as M
17−import Data.Tagged
18−import Data.Void
19−import qualified Data.TypeRepMap as T
20−import Type.Reflection
21−
22−data Progress a = Finished a | Started | TyingKnot Dynamic
23−
24−data MemoMap a where
25− MemoMap :: !(M.Map k (Progress v)) -> MemoMap (k, v)
26−
27−data MemoState s = MemoState s (T.TypeRepMap MemoMap)
28−
29−-- | An effectful memoization monad.
30−type MonadMemo s m = MonadState (MemoState s) m
31−
32−memoStateLookup
33− :: forall k v s. (Typeable k, Typeable v, Ord k)
34− => k -> MemoState s -> Maybe (Progress v)
35−memoStateLookup k (MemoState _ t) = case T.lookup @(k, v) t of
36− Just (MemoMap m) -> M.lookup k m
37− Nothing -> Nothing
38−
39−memoStateInsert
40− :: forall k v s. (Typeable k, Typeable v, Ord k)
41− => k -> Progress v -> MemoState s -> MemoState s
42−memoStateInsert k x (MemoState s t) = MemoState s $ T.insert (MemoMap m'') t
43− where
44− m'' = M.insert k x m'
45− m' = case T.lookup @(k, v) t of
46− Just (MemoMap m) -> m
47− Nothing -> M.empty
48−
49−modifyMemoNonce :: MonadMemo s m => (s -> s) -> m s
50−modifyMemoNonce f = do
51− MemoState s t <- get
52− put $ MemoState (f s) t
53− pure s
54−
55−-- | Run a memoized computation.
56−runMemo :: Monad m => s -> StateT (MemoState s) m a -> m a
57−runMemo s = (`evalStateT` MemoState s T.empty)
58−
59−-- | A description of how to effectfully tie knots in type @v@, using the @m@
60−-- monad, and by sharing some @d@ data among the recursive instances.
61−data KnotTier v d m = KnotTier
62− { onKnotFound :: m d -- ^ Create some data that will be connected to this knot
63− , onKnotUsed :: d -> m v -- ^ This is what the knot will look like as a value
64− -- to the inner computations
65− , tieKnot :: d -> v -> m v -- ^ Once we're done and we're outside, tie the
66− -- knot using the datum
67− }
68−
69−unknot :: KnotTier v Void m
70−unknot = KnotTier
71− { onKnotFound = error "Recursion detected"
72− , onKnotUsed = absurd
73− , tieKnot = absurd
74− }
75−
76−-- | Run a potentially recursive computation. The provided key will be used to
77−-- refer to the result of this computation. If during the computation, another
78−-- attempt to run the computation with the same key is made, we run a
79−-- tying-the-knot procedure.
80−--
81−-- If another attempt to run the computation with the same key is made
82−-- *after we're done*, we will return the memoized value.
83−memoWithKnot
84− :: forall k v d m s.
85− (Typeable k, Typeable v, Typeable d, Ord k, MonadMemo s m)
86− => KnotTier v d m
87− -> m v -- ^ the computation to memoize
88− -> k -- ^ key for memoization
89− -> m v
90−memoWithKnot tier f k = memoStateLookup @k @v k <$> get >>= \case
91− Just (Finished v) -> pure v
92− Just Started -> do
93− d <- onKnotFound tier
94− modify $ memoStateInsert @k @v k (TyingKnot $ toDyn d)
95− onKnotUsed tier d
96− Just (TyingKnot dyn) -> case fromDynamic dyn of
97− Just d -> onKnotUsed tier d
98− Nothing -> error $ "Type mismatch when examining the knot of "
99− <> show (typeRep @(k -> v)) <> ": expected " <> show (typeRep @d)
100− <> ", got " <> show (dynTypeRep dyn)
101− Nothing -> do
102− modify $ memoStateInsert @k @v k Started
103− v <- f
104− v' <- memoStateLookup @k @v k <$> get >>= \case
105− Just Started -> pure v
106− Just (TyingKnot dyn) -> case fromDynamic dyn of
107− Just d -> tieKnot tier d v
108− Nothing -> error $ "Type mismatch when tying the knot of "
109− <> show (typeRep @(k -> v)) <> ": expected " <> show (typeRep @d)
110− <> ", got " <> show (dynTypeRep dyn)
111− Just (Finished _) -> error $ "Unexpected Finished when memoizing "
112− <> show (typeRep @(k -> v))
113− Nothing -> pure v
114− -- Normally this would be an error, but the underlying monad can refuse
115− -- to remember memoization state
116− modify $ memoStateInsert @k @v k (Finished v')
117− pure v'
118−
119−-- | Disambiguate memoized computations with an arbitrary tag.
120−memoTaggedWithKnot
121− :: forall t k v d m s.
122− ( Typeable t, Typeable k, Typeable v, Typeable d
123− , Ord k, MonadMemo s m )
124− => KnotTier v d m -> m v -> k -> m v
125−memoTaggedWithKnot tier f k = withTypeable (typeRepKind $ typeRep @t) $
126− memoWithKnot tier f (Tagged @t k)
src/OpenAPI/Checker/Options.hsdeleted−65
@@ -1,65 +0,0 @@
1−module OpenAPI.Checker.Options
2− ( Options (..)
3− , Mode (..)
4− , OutputMode (..)
5− , optionsParserInfo
6− , execParser
7− )
8−where
9−
10−import GHC.Generics (Generic)
11−import Options.Applicative
12−
13−data Options = Options
14− { clientFile :: FilePath
15− , serverFile :: FilePath
16− , mode :: Mode
17− , outputMode :: OutputMode
18− }
19− deriving stock (Generic)
20−
21−data Mode = Silent | OnlyErrors | All
22−
23−data OutputMode = StdoutMode | FileMode FilePath
24−
25−optionsParserInfo :: ParserInfo Options
26−optionsParserInfo =
27− info
28− (helper <*> optionsParser)
29− (fullDesc
30− <> header "openapi-diff"
31− <> progDesc "A tool to check compatibility between two OpenApi specifications.")
32−
33−optionsParser :: Parser Options
34−optionsParser =
35− Options
36− <$> strOption
37− (short 'c'
38− <> long "client"
39− <> help "The specification that will be used for the client of the API.")
40− <*> strOption
41− (short 's'
42− <> long "server"
43− <> help "The specification that will be used for the server of the API.")
44− <*> (flag'
45− Silent
46− (long "silent"
47− <> help "Silence all output.")
48− <|> flag'
49− OnlyErrors
50− (long "only-errors"
51− <> help "Only report incompatibility errors in the output.")
52− <|> flag'
53− All
54− (long "all"
55− <> help
56− "Report both incompatible and compatible changes. \
57− \Compatible changes will not trigger a failure exit code.")
58− <|> pure All)
59− <*> (pure StdoutMode
60− <|> (FileMode
61− <$> strOption
62− (short 'o' <> long "output"
63− <> help
64− "The file path where the output should be writtrn. \
65− \Leave blank to output result to stdout.")))
src/OpenAPI/Checker/Report.hsdeleted−136
@@ -1,136 +0,0 @@
1−module OpenAPI.Checker.Report
2− ( generateReport
3− )
4−where
5−
6−import Control.Monad.Reader
7−import Control.Monad.Writer
8−import Data.Foldable
9−import Data.Functor
10−import qualified Data.Map as M
11−import Data.Maybe
12−import qualified Data.Text as T
13−import Data.Traversable
14−import Data.TypeRepMap hiding (empty)
15−import Data.Typeable
16−import OpenAPI.Checker.Behavior
17−import OpenAPI.Checker.Paths
18−import OpenAPI.Checker.PathsPrefixTree hiding (empty)
19−import qualified OpenAPI.Checker.PathsPrefixTree as P hiding (empty)
20−import OpenAPI.Checker.Validate.OpenApi
21−import Text.Pandoc.Builder
22−
23−generateReport :: Either (P.PathsPrefixTree Behave AnIssue 'APILevel) () -> Pandoc
24−generateReport (Right ()) = doc $ header 1 "No breaking changes found ✨"
25−generateReport (Left errs) = doc $ runReportMonad jets $ showErrs errs
26−
27−data ReportState = ReportState
28− { sourceJets :: [SomeReportJet Behave]
29− , headerLevel :: Int
30− }
31−
32−type ReportMonad = ReaderT ReportState (Writer Blocks)
33−
34−runReportMonad :: [SomeReportJet Behave] -> ReportMonad () -> Blocks
35−runReportMonad jts =
36− execWriter
37− . flip
38− runReaderT
39− ReportState
40− { sourceJets = jts
41− , headerLevel = 1
42− }
43−
44−smartHeader :: Inlines -> ReportMonad ()
45−smartHeader i = do
46− h <- asks headerLevel
47− tell $ header h i
48−
49−showErrs :: Typeable a => P.PathsPrefixTree Behave AnIssue a -> ReportMonad ()
50−showErrs x@(P.PathsPrefixNode currentIssues _) = do
51− jts <- asks sourceJets
52− for_ currentIssues $ \(AnIssue i) -> tell . describeIssue $ i
53− unfoldM x (observeSomeJetShowErrs <$> jts) $ \(P.PathsPrefixNode _ subIssues) -> do
54− for_ subIssues $ \(WrapTypeable (AStep m)) ->
55− for_ (M.toList m) $ \(bhv, subErrors) -> do
56− unless (P.null subErrors) $ do
57− smartHeader $ describeBehaviour bhv
58− incrementHeaders $ showErrs subErrors
59−
60−unfoldM :: Monad m => a -> [a -> m a] -> (a -> m ()) -> m ()
61−unfoldM a [] g = g a
62−unfoldM a (f : ff) g = do
63− a' <- f a
64− unfoldM a' ff g
65−
66−observeSomeJetShowErrs
67− :: forall a.
68− Typeable a
69− => SomeReportJet Behave
70− -> P.PathsPrefixTree Behave AnIssue a
71− -> ReportMonad (P.PathsPrefixTree Behave AnIssue a)
72−observeSomeJetShowErrs (SomeReportJet (Proxy :: Proxy a') f) x
73− | Just Refl <- eqT @a @a' = observeJetShowErrs f x
74−observeSomeJetShowErrs _ x = pure x
75−
76−observeJetShowErrs :: ReportJet Behave a -> P.PathsPrefixTree Behave AnIssue a -> ReportMonad (P.PathsPrefixTree Behave AnIssue a)
77−observeJetShowErrs jet (P.PathsPrefixNode currentIssues subIssues) = do
78− rest <- fmap (fold . join) $
79− for subIssues $ \(WrapTypeable (AStep m)) -> fmap catMaybes $
80− for (M.toList m) $ \(bhv, subErrs) ->
81− case applyReportJet jet bhv of
82− Just (Left h) -> do
83− smartHeader h
84− incrementHeaders $ showErrs subErrs
85− return Nothing
86− Just (Right jet') -> do
87− rest <- observeJetShowErrs jet' subErrs
88− return $ Just $ embed (step bhv) rest
89− Nothing -> return $ Just $ embed (step bhv) subErrs
90− return $ PathsPrefixNode currentIssues mempty <> rest
91−
92−-- | A "jet" is a way of simplifying expressions from "outside". The "jetted"
93−-- expressions should still be completely valid and correct without the jets.
94−-- Jets just make the expression more "optimized" by identifying patterns and
95−-- replacing the expressions with "better" ones that have the same sematics.
96−--
97−-- The tem "jet" in this context was introduced in the Urbit project:
98−-- https://urbit.org/docs/vere/jetting/
99−--
100−-- The pattern fits well for simplifying 'Behaviour' tree paths.
101−class ConstructReportJet f a b c where
102− constructReportJet :: (f a b -> c) -> ReportJet f a
103−
104−instance (ConstructReportJet f b c d, Typeable b) => ConstructReportJet f a b (f b c -> d) where
105− constructReportJet f = ReportJet Proxy $ \x -> constructReportJet $ f x
106−
107−instance Typeable b => ConstructReportJet f a b Inlines where
108− constructReportJet f = TerminalJet Proxy f
109−
110−constructSomeReportJet :: (ConstructReportJet f a b c, Typeable a) => (f a b -> c) -> SomeReportJet f
111−constructSomeReportJet = SomeReportJet Proxy . constructReportJet
112−
113−data ReportJet f a where
114− ReportJet :: Typeable b => Proxy b -> (f a b -> ReportJet f b) -> ReportJet f a
115− TerminalJet :: Typeable b => Proxy b -> (f a b -> Inlines) -> ReportJet f a
116−
117−data SomeReportJet f where
118− SomeReportJet :: Typeable a => Proxy a -> ReportJet f a -> SomeReportJet f
119−
120−applyReportJet :: forall f a b. Typeable b => ReportJet f a -> f a b -> Maybe (Either Inlines (ReportJet f b))
121−applyReportJet (TerminalJet (Proxy :: Proxy b') f) x = eqT @b @b' <&> \Refl -> Left $ f x
122−applyReportJet (ReportJet (Proxy :: Proxy b') f) x = eqT @b @b' <&> \Refl -> Right $ f x
123−
124−incrementHeaders :: ReportMonad x -> ReportMonad x
125−incrementHeaders m = do
126− l <- asks headerLevel
127− local (\x -> x {headerLevel = l + 1}) m
128−
129−jets :: [SomeReportJet Behave]
130−jets =
131− [ constructSomeReportJet $ \p@(AtPath _) op@(InOperation _) ->
132− strong (describeBehaviour op) <> " " <> describeBehaviour p :: Inlines
133− , constructSomeReportJet $ \InRequest InPayload PayloadSchema -> "JSON Request" :: Inlines
134− , constructSomeReportJet $ \(WithStatusCode c) ResponsePayload PayloadSchema ->
135− "JSON Response – " <> str (T.pack . show $ c) :: Inlines
136− ]
src/OpenAPI/Checker/Subtree.hsdeleted−314
@@ -1,314 +0,0 @@
1−{-# OPTIONS_GHC -Wno-orphans #-}
2−
3−module OpenAPI.Checker.Subtree
4− ( Steppable (..)
5− , Step (..)
6− , TraceRoot
7− , Trace
8− , Traced
9− , Traced'
10− , pattern Traced
11− , traced
12− , retraced
13− , stepTraced
14− , Subtree (..)
15− , checkCompatibility
16− , checkSubstructure
17− , CompatM (..)
18− , CompatFormula'
19− , SemanticCompatFormula
20− , ProdCons (..)
21− , HasUnsupportedFeature (..)
22− , swapProdCons
23− , runCompatFormula
24− , issueAt
25− , anyOfAt
26− , structuralIssue
27−
28− -- * Structural helpers
29− , structuralMaybe
30− , structuralMaybeWith
31− , structuralEq
32− , iohmStructural
33− , iohmStructuralWith
34− , structuralList
35−
36− -- * Reexports
37− , (>>>)
38− , (<<<)
39− , extract
40− , ask
41− , local
42− , step
43− , Typeable
44− )
45−where
46−
47−import Control.Comonad.Env
48−import Control.Monad.Identity
49−import Control.Monad.State
50−import Data.Foldable
51−import Data.Functor.Compose
52−import Data.HList
53−import qualified Data.HashMap.Strict.InsOrd as IOHM
54−import Data.Hashable
55−import Data.Kind
56−import Data.Monoid
57−import Data.OpenApi
58−import qualified Data.Set as S
59−import Data.Typeable
60−import OpenAPI.Checker.Behavior
61−import OpenAPI.Checker.Formula
62−import OpenAPI.Checker.Memo
63−import OpenAPI.Checker.Paths
64−import qualified OpenAPI.Checker.PathsPrefixTree as P
65−
66−class
67− (Typeable Step, Typeable a, Typeable b, Ord (Step a b), Show (Step a b)) =>
68− Steppable (a :: Type) (b :: Type)
69− where
70− -- | How to get from an @a@ node to a @b@ node
71− data Step a b :: Type
72−
73−data TraceRoot
74−
75−instance Steppable TraceRoot OpenApi where
76− data Step TraceRoot OpenApi
77− = ClientSchema
78− | ServerSchema
79− deriving stock (Eq, Ord, Show)
80−
81−type Trace = Paths Step TraceRoot
82−
83−type instance AdditionalQuiverConstraints Step a b = ()
84−
85−type Traced' a b = Env (Trace a) b
86−
87−type Traced a = Traced' a a
88−
89−pattern Traced :: Trace a -> b -> Traced' a b
90−pattern Traced t x = EnvT t (Identity x)
91−
92−{-# COMPLETE Traced #-}
93−
94−traced :: Trace a -> a -> Traced a
95−traced = env
96−
97−retraced :: (Trace a -> Trace a') -> Traced' a b -> Traced' a' b
98−retraced f (Traced a b) = Traced (f a) b
99−
100−stepTraced :: Steppable a a' => Step a a' -> Traced' a b -> Traced' a' b
101−stepTraced s = retraced (>>> step s)
102−
103−data ProdCons a = ProdCons
104− { producer :: a
105− , consumer :: a
106− }
107− deriving (Eq, Ord, Show, Functor, Foldable, Traversable)
108−
109−swapProdCons :: ProdCons a -> ProdCons a
110−swapProdCons (ProdCons a b) = ProdCons b a
111−
112−instance Applicative ProdCons where
113− pure x = ProdCons x x
114− ProdCons fp fc <*> ProdCons xp xc = ProdCons (fp xp) (fc xc)
115−
116−newtype CompatM a = CompatM
117− { unCompatM
118− :: StateT (MemoState VarRef) Identity a
119− }
120− deriving newtype
121− ( Functor
122− , Applicative
123− , Monad
124− , MonadState (MemoState VarRef)
125− )
126−
127−type CompatFormula' q f r = Compose CompatM (FormulaF q f r)
128−
129−type SemanticCompatFormula = CompatFormula' Behave AnIssue 'APILevel
130−
131−type StructuralCompatFormula = CompatFormula' VoidQuiver Proxy ()
132−
133−data VoidQuiver a b
134−
135−deriving stock instance Eq (VoidQuiver a b)
136−
137−type instance AdditionalQuiverConstraints VoidQuiver a b = ()
138−
139−deriving stock instance Ord (VoidQuiver a b)
140−
141−deriving stock instance Show (VoidQuiver a b)
142−
143−class (Typeable t, Issuable (SubtreeLevel t)) => Subtree (t :: Type) where
144− type CheckEnv t :: [Type]
145− type SubtreeLevel t :: BehaviorLevel
146−
147− checkStructuralCompatibility
148− :: (HasAll (CheckEnv t) xs)
149− => HList xs
150− -> ProdCons (Traced t)
151− -> StructuralCompatFormula ()
152−
153− checkSemanticCompatibility
154− :: (HasAll (CheckEnv t) xs)
155− => HList xs
156− -> Behavior (SubtreeLevel t)
157− -> ProdCons (Traced t)
158− -> SemanticCompatFormula ()
159−
160−{-# WARNING checkStructuralCompatibility "You should not be calling this directly. Use 'checkSubstructure'" #-}
161−
162−{-# WARNING checkSemanticCompatibility "You should not be calling this directly. Use 'checkCompatibility'" #-}
163−
164−checkCompatibility
165− :: (HasAll (CheckEnv t) xs, Subtree t)
166− => HList xs
167− -> Behavior (SubtreeLevel t)
168− -> ProdCons (Traced t)
169− -> SemanticCompatFormula ()
170−checkCompatibility e bhv = memo bhv SemanticMemoKey $ \pc ->
171− case runCompatFormula $ checkSubstructure e pc of
172− Left _ -> checkSemanticCompatibility e bhv pc
173− Right () -> pure ()
174−
175−checkSubstructure
176− :: (HasAll (CheckEnv t) xs, Subtree t)
177− => HList xs
178− -> ProdCons (Traced t)
179− -> StructuralCompatFormula ()
180−checkSubstructure e = memo Root StructuralMemoKey $ checkStructuralCompatibility e
181−
182−structuralMaybe
183− :: (Subtree a, HasAll (CheckEnv a) xs)
184− => HList xs
185− -> ProdCons (Maybe (Traced a))
186− -> StructuralCompatFormula ()
187−structuralMaybe e = structuralMaybeWith (checkSubstructure e)
188−
189−structuralMaybeWith
190− :: (ProdCons a -> StructuralCompatFormula ())
191− -> ProdCons (Maybe a)
192− -> StructuralCompatFormula ()
193−structuralMaybeWith f (ProdCons (Just a) (Just b)) = f $ ProdCons a b
194−structuralMaybeWith _ (ProdCons Nothing Nothing) = pure ()
195−structuralMaybeWith _ _ = structuralIssue
196−
197−structuralList
198− :: (Subtree a, HasAll (CheckEnv a) xs)
199− => HList xs
200− -> ProdCons [Traced a]
201− -> StructuralCompatFormula ()
202−structuralList _ (ProdCons [] []) = pure ()
203−structuralList e (ProdCons (a : aa) (b : bb)) = do
204− checkSubstructure e $ ProdCons a b
205− structuralList e $ ProdCons aa bb
206− pure ()
207−structuralList _ _ = structuralIssue
208−
209−structuralEq :: (Eq a, Comonad w) => ProdCons (w a) -> StructuralCompatFormula ()
210−structuralEq (ProdCons a b) = if extract a == extract b then pure () else structuralIssue
211−
212−iohmStructural
213− :: (HasAll (CheckEnv v) (k ': xs), Ord k, Subtree v, Hashable k, Typeable k, Show k)
214− => HList xs
215− -> ProdCons (Traced (IOHM.InsOrdHashMap k v))
216− -> StructuralCompatFormula ()
217−iohmStructural e =
218− iohmStructuralWith (\k -> checkSubstructure (k `HCons` e))
219−
220−instance (Typeable k, Typeable v, Ord k, Show k) => Steppable (IOHM.InsOrdHashMap k v) v where
221− data Step (IOHM.InsOrdHashMap k v) v = InsOrdHashMapKeyStep k
222− deriving (Eq, Ord, Show)
223−
224−iohmStructuralWith
225− :: (Ord k, Hashable k, Typeable k, Typeable v, Show k)
226− => (k -> ProdCons (Traced v) -> StructuralCompatFormula ())
227− -> ProdCons (Traced (IOHM.InsOrdHashMap k v))
228− -> StructuralCompatFormula ()
229−iohmStructuralWith f pc = do
230− let ProdCons pEKeys cEKeys = S.fromList . IOHM.keys . extract <$> pc
231− if pEKeys == cEKeys
232− then
233− for_
234− pEKeys
235− (\eKey ->
236− f eKey $ stepTraced (InsOrdHashMapKeyStep eKey) . fmap (IOHM.lookupDefault (error "impossible") eKey) <$> pc)
237− else structuralIssue
238−
239−class HasUnsupportedFeature x where
240− hasUnsupportedFeature :: x -> Bool
241−
242−instance HasUnsupportedFeature () where
243− hasUnsupportedFeature () = False
244−
245−instance
246− (HasUnsupportedFeature a, HasUnsupportedFeature b)
247− => HasUnsupportedFeature (Either a b)
248− where
249− hasUnsupportedFeature (Left x) = hasUnsupportedFeature x
250− hasUnsupportedFeature (Right x) = hasUnsupportedFeature x
251−
252−instance Issuable l => HasUnsupportedFeature (Issue l) where
253− hasUnsupportedFeature = issueIsUnsupported
254−
255−instance HasUnsupportedFeature (AnIssue l) where
256− hasUnsupportedFeature (AnIssue issue) = hasUnsupportedFeature issue
257−
258−instance
259− (forall x. HasUnsupportedFeature (f x))
260− => HasUnsupportedFeature (P.PathsPrefixTree q f r)
261− where
262− hasUnsupportedFeature =
263− getAny . P.foldWith (\_ fa -> Any $ hasUnsupportedFeature fa)
264−
265−runCompatFormula
266− :: CompatFormula' q f r a
267− -> Either (P.PathsPrefixTree q f r) a
268−runCompatFormula (Compose f) =
269− calculate . runIdentity . runMemo 0 . unCompatM $ f
270−
271−issueAt :: Issuable l => Paths q r l -> Issue l -> CompatFormula' q AnIssue r a
272−issueAt xs issue = Compose $ pure $ anError $ AnItem xs $ AnIssue issue
273−
274−structuralIssue :: StructuralCompatFormula a
275−structuralIssue = Compose $ pure $ anError $ AnItem Root Proxy
276−
277−anyOfAt
278− :: Issuable l
279− => Paths q r l
280− -> Issue l
281− -> [CompatFormula' q AnIssue r a]
282− -> CompatFormula' q AnIssue r a
283−anyOfAt _ _ [x] = x
284−anyOfAt xs issue fs =
285− Compose $ (`eitherOf` AnItem xs (AnIssue issue)) <$> sequenceA (getCompose <$> fs)
286−
287−fixpointKnot
288− :: MonadState (MemoState VarRef) m
289− => KnotTier (FormulaF q f r ()) VarRef m
290−fixpointKnot =
291− KnotTier
292− { onKnotFound = modifyMemoNonce succ
293− , onKnotUsed = \i -> pure $ variable i
294− , tieKnot = \i x -> pure $ maxFixpoint i x
295− }
296−
297−memo
298− :: (Typeable (l :: k), Typeable q, Typeable f, Typeable k, Typeable a)
299− => Paths q r l
300− -> MemoKey
301− -> (ProdCons (Traced a) -> CompatFormula' q f r ())
302− -> (ProdCons (Traced a) -> CompatFormula' q f r ())
303−memo bhv k f pc = Compose $ do
304− formula' <-
305− memoWithKnot
306− fixpointKnot
307− (do
308− formula <- getCompose $ f pc
309− pure $ mapErrors (P.filter bhv) formula)
310− (k, ask <$> pc)
311− pure $ mapErrors (P.embed bhv) formula'
312−
313−data MemoKey = SemanticMemoKey | StructuralMemoKey
314− deriving stock (Eq, Ord)
src/OpenAPI/Checker/Subtree/Deriving.hsdeleted−6
@@ -1,6 +0,0 @@
1−module OpenAPI.Checker.Subtree.Deriving (EqSubtree (..)) where
2−
3−import Control.Monad
4−import OpenAPI.Checker.Subtree
5−
6−newtype EqSubtree t = EqSubtree t
src/OpenAPI/Checker/Validate/Products.hsdeleted−49
@@ -1,49 +0,0 @@
1−{- | Checks product-like entities. The key is some identificator for the product
2−element. Each element may be required or optional.
3−
4−One example of product is request parameters. There are optional and required
5−parameters. The client and server have possibly different set of
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.
8−
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)
11−and their schemas match.
12−
13−This module abstracts this logic for arbitrary elements -}
14−
15−module OpenAPI.Checker.Validate.Products
16− ( checkProducts
17− , ProductLike(..)
18− ) where
19−
20−import Data.Foldable
21−import Data.Map.Strict (Map)
22−import qualified Data.Map.Strict as M
23−import OpenAPI.Checker.Behavior
24−import OpenAPI.Checker.Paths
25−import OpenAPI.Checker.Subtree
26−
27−-- | Some entity which is product-like
28−data ProductLike a = ProductLike
29− { productValue :: a
30− , required :: Bool
31− }
32−
33−checkProducts
34− :: (Ord k, Issuable l)
35− => Paths q r l
36− -> (k -> Issue l)
37− -- ^ No required element found
38− -> (k -> ProdCons t -> CompatFormula' q AnIssue r ())
39− -> ProdCons (Map k (ProductLike t))
40− -> CompatFormula' q AnIssue r ()
41−checkProducts xs noElt check (ProdCons p c) = for_ (M.toList c) $ \(key, consElt) ->
42− case M.lookup key p of
43− Nothing -> case required consElt of
44− True -> issueAt xs $ noElt key
45− False -> pure ()
46− Just prodElt -> do
47− let
48− elts = ProdCons prodElt consElt
49− check key (productValue <$> elts)
src/OpenAPI/Checker/Validate/Schema.hsdeleted−1187
@@ -1,1187 +0,0 @@
1−{-# OPTIONS_GHC -fno-warn-orphans #-}
2−
3−module OpenAPI.Checker.Validate.Schema
4− ( JsonType (..)
5− , ForeachType (..)
6− , foldType
7− , forType_
8− , TypedValue (..)
9− , untypeValue
10− , Bound (..)
11− , schemaToFormula
12− , foldLattice
13− )
14−where
15−
16−import Algebra.Lattice
17−import Control.Applicative
18−import Control.Arrow
19−import Control.Comonad.Env hiding (env)
20−import Control.Lens hiding (cons, para)
21−import Control.Monad.Reader hiding (ask)
22−import qualified Control.Monad.Reader as R
23−import Control.Monad.State
24−import Control.Monad.Writer
25−import qualified Data.Aeson as A
26−import qualified Data.ByteString.Lazy as BSL
27−import Data.Coerce
28−import qualified Data.Foldable as F
29−import Data.HList
30−import qualified Data.HashMap.Strict as HM
31−import qualified Data.HashMap.Strict.InsOrd as IOHM
32−import Data.Int
33−import Data.Kind
34−import qualified Data.List.NonEmpty as NE
35−import qualified Data.Map as M
36−import Data.Maybe
37−import Data.OpenApi hiding (get)
38−import Data.Ord
39−import Data.Ratio
40−import Data.Scientific
41−import qualified Data.Set as S
42−import Data.Text (Text)
43−import qualified Data.Text as T hiding (singleton)
44−import qualified Data.Text.Encoding as T
45−import Data.Typeable
46−import OpenAPI.Checker.Behavior
47−import OpenAPI.Checker.Memo
48−import OpenAPI.Checker.Orphans ()
49−import OpenAPI.Checker.Paths
50−import qualified OpenAPI.Checker.PathsPrefixTree as P
51−import OpenAPI.Checker.References
52−import OpenAPI.Checker.Subtree
53−import Text.Pandoc.Builder hiding (Format, Null)
54−import Text.Regex.Pcre2
55−
56−-- | Type of a JSON value
57−data JsonType
58− = Null
59− | Boolean
60− | Number
61− | String
62− | Array
63− | Object
64− deriving stock (Eq, Ord, Show)
65−
66−-- | A 'A.Value' whose type we know
67−data TypedValue :: JsonType -> Type where
68− TNull :: TypedValue 'Null
69− TBool :: !Bool -> TypedValue 'Boolean
70− TNumber :: !Scientific -> TypedValue 'Number
71− TString :: !Text -> TypedValue 'String
72− TArray :: !A.Array -> TypedValue 'Array
73− TObject :: !A.Object -> TypedValue 'Object
74−
75−deriving stock instance Eq (TypedValue t)
76−
77−deriving stock instance Ord (TypedValue t)
78−
79−deriving stock instance Show (TypedValue t)
80−
81−untypeValue :: TypedValue t -> A.Value
82−untypeValue TNull = A.Null
83−untypeValue (TBool b) = A.Bool b
84−untypeValue (TNumber n) = A.Number n
85−untypeValue (TString s) = A.String s
86−untypeValue (TArray a) = A.Array a
87−untypeValue (TObject o) = A.Object o
88−
89−data Bound a = Exclusive !a | Inclusive !a
90− deriving (Eq, Show, Functor)
91−
92−-- | The order is lexicographical on @a * Bool@.
93−instance Ord a => Ord (Bound a) where
94− Exclusive a `compare` Exclusive b = compare a b
95− Exclusive a `compare` Inclusive b = if a <= b then LT else GT
96− Inclusive a `compare` Exclusive b = if a < b then LT else GT
97− Inclusive a `compare` Inclusive b = compare a b
98−
99−data Property = Property
100− { propRequired :: Bool
101− , propFormula :: ForeachType JsonFormula
102− , propRefSchema :: Traced (Referenced Schema)
103− }
104− deriving stock (Eq, Ord, Show)
105−
106−-- | A primitive structural condition for the "top level" of a JSON value (of a specific type)
107−data Condition :: JsonType -> Type where
108− Exactly :: TypedValue t -> Condition t
109− Maximum :: !(Bound Scientific) -> Condition 'Number
110− Minimum
111− :: !(Down (Bound (Down Scientific)))
112− -> Condition 'Number -- ^ this has the right Ord
113− MultipleOf :: !Scientific -> Condition 'Number
114− NumberFormat :: !Format -> Condition 'Number
115− MaxLength :: !Integer -> Condition 'String
116− MinLength :: !Integer -> Condition 'String
117− Pattern :: !Pattern -> Condition 'String
118− StringFormat :: !Format -> Condition 'String
119− Items
120− :: !(ForeachType JsonFormula)
121− -> !(Traced (Referenced Schema))
122− -> Condition 'Array
123− MaxItems :: !Integer -> Condition 'Array
124− MinItems :: !Integer -> Condition 'Array
125− UniqueItems :: Condition 'Array
126− Properties
127− :: !(M.Map Text Property)
128− -> !(ForeachType JsonFormula) -- ^ formula for additional properties
129− -> !(Maybe (Traced (Referenced Schema))) -- ^ schema for additional properties, Nothing means bottom
130− -> Condition 'Object
131− MaxProperties :: !Integer -> Condition 'Object
132− MinProperties :: !Integer -> Condition 'Object
133−
134−showCondition :: Condition a -> Blocks
135−showCondition = \case
136− (Exactly v) -> para "The value should be:" <> showJSONValue (untypeValue v)
137− (Maximum b) -> para $ "The value should be less than " <> showBound b <> "."
138− (Minimum (Down b)) -> para $ "The value should be more than " <> showBound (getDown <$> b) <> "."
139− (MultipleOf n) -> para $ "The value should be a multiple of " <> show' n <> "."
140− (NumberFormat p) -> para $ "The number should have the following format:" <> code p <> "."
141− (Pattern p) -> para "The value should satisfy the following pattern (regular expression):" <> codeBlock p
142− (StringFormat p) -> para $ "The string should have the following format:" <> code p <> "."
143− (MaxLength p) -> para $ "The length of the string should be less than or equal to " <> show' p <> "."
144− (MinLength p) -> para $ "The length of the string should be more than or equal to " <> show' p <> "."
145− (Items i _) -> para "The items of the array should satisfy:" <> showForEachJsonFormula i
146− (MaxItems n) -> para $ "The length of the array should be less than or equal to " <> show' n <> "."
147− (MinItems n) -> para $ "The length of the array should be more than or equal to " <> show' n <> "."
148− UniqueItems -> para "The elements in the array should be unique."
149− (Properties props additional _) ->
150− bulletList $
151− (M.toList props
152− <&> (\(k, p) ->
153− para (code k)
154− <> para (strong $ if propRequired p then "Required" else "Optional")
155− <> showForEachJsonFormula (propFormula p)))
156− <> [ para (emph "Additional properties")
157− <> showForEachJsonFormula additional
158− ]
159− (MaxProperties n) -> para $ "The maximum number of fields should be " <> show' n <> "."
160− (MinProperties n) -> para $ "The minimum number of fields should be " <> show' n <> "."
161− where
162− showForEachJsonFormula :: ForeachType JsonFormula -> Blocks
163− showForEachJsonFormula i =
164− bulletList $
165− foldType
166− (\t f ->
167− let (DNF conds') = f i
168− conds = S.toList <$> S.toList conds'
169− in [ para (describeJSONType t)
170− <> bulletList (conds <&> \cond -> bulletList (showCondition <$> cond))
171− ])
172−
173−satisfiesTyped :: TypedValue t -> Condition t -> Bool
174−satisfiesTyped e (Exactly e') = e == e'
175−satisfiesTyped (TNumber n) (Maximum (Exclusive m)) = n < m
176−satisfiesTyped (TNumber n) (Maximum (Inclusive m)) = n <= m
177−satisfiesTyped (TNumber n) (Minimum (Down (Exclusive (Down m)))) = n > m
178−satisfiesTyped (TNumber n) (Minimum (Down (Inclusive (Down m)))) = n >= m
179−satisfiesTyped (TNumber n) (MultipleOf m) = denominator (toRational n / toRational m) == 1 -- TODO: could be better #36
180−satisfiesTyped (TNumber n) (NumberFormat f) = checkNumberFormat f n
181−satisfiesTyped (TString s) (MaxLength m) = fromIntegral (T.length s) <= m
182−satisfiesTyped (TString s) (MinLength m) = fromIntegral (T.length s) >= m
183−satisfiesTyped (TString s) (Pattern p) = isJust $ match p s -- TODO: regex stuff #32
184−satisfiesTyped (TString s) (StringFormat f) = checkStringFormat f s
185−satisfiesTyped (TArray a) (Items f _) = all (`satisfies` f) a
186−satisfiesTyped (TArray a) (MaxItems m) = fromIntegral (F.length a) <= m
187−satisfiesTyped (TArray a) (MinItems m) = fromIntegral (F.length a) >= m
188−satisfiesTyped (TArray a) UniqueItems = S.size (S.fromList $ F.toList a) == F.length a -- TODO: could be better #36
189−satisfiesTyped (TObject o) (Properties props additional _) =
190− all (`HM.member` o) (M.keys (M.filter propRequired props))
191− && all (\(k, v) -> satisfies v $ maybe additional propFormula $ M.lookup k props) (HM.toList o)
192−satisfiesTyped (TObject o) (MaxProperties m) = fromIntegral (HM.size o) <= m
193−satisfiesTyped (TObject o) (MinProperties m) = fromIntegral (HM.size o) >= m
194−
195−checkNumberFormat :: Format -> Scientific -> Bool
196−checkNumberFormat "int32" (toRational -> n) =
197− denominator n == 1
198− && n >= toRational (minBound :: Int32)
199− && n <= toRational (maxBound :: Int32)
200−checkNumberFormat "int64" (toRational -> n) =
201− denominator n == 1
202− && n >= toRational (minBound :: Int64)
203− && n <= toRational (maxBound :: Int64)
204−checkNumberFormat "float" _n = True
205−checkNumberFormat "double" _n = True
206−checkNumberFormat f _n = error $ "Invalid number format: " <> T.unpack f
207−
208−checkStringFormat :: Format -> Text -> Bool
209−checkStringFormat "byte" _s = True -- TODO: regex stuff #32
210−checkStringFormat "binary" _s = True
211−checkStringFormat "date" _s = True
212−checkStringFormat "date-time" _s = True
213−checkStringFormat "password" _s = True
214−checkStringFormat "uuid" _s = True
215−checkStringFormat f _s = error $ "Invalid string format: " <> T.unpack f
216−
217−deriving stock instance Eq (Condition t)
218−
219−deriving stock instance Ord (Condition t)
220−
221−deriving stock instance Show (Condition t)
222−
223−data SomeCondition where
224− SomeCondition :: Typeable t => Condition t -> SomeCondition
225−
226−instance Eq SomeCondition where
227− SomeCondition x == SomeCondition y = case cast x of
228− Just x' -> x' == y
229− Nothing -> False
230−
231−instance Ord SomeCondition where
232− compare (SomeCondition x) (SomeCondition y) = case cast x of
233− Just x' -> compare x' y
234− Nothing -> compare (typeRep x) (typeRep y)
235−
236−deriving stock instance Show SomeCondition
237−
238−-- | A boolean formula (without "not") of 'Condition's. Represented as a
239−-- Disjunctive Normal Form: the formula is a disjunction of a set of conjuncts,
240−-- each of which is a conjunction of a set of 'Condition's.
241−newtype JsonFormula t
242− = DNF (S.Set (S.Set (Condition t)))
243− deriving stock (Eq, Ord, Show)
244−
245−disjAdd
246− :: JsonFormula t
247− -> S.Set (Condition t)
248− -> JsonFormula t
249−disjAdd (DNF yss) xs
250− | any (`S.isSubsetOf` xs) yss = DNF yss
251− | otherwise = DNF $ S.insert xs $ S.filter (not . S.isSubsetOf xs) yss
252−
253−instance Lattice (JsonFormula t) where
254− xss \/ DNF yss = S.foldl' disjAdd xss yss
255− DNF xss /\ DNF yss =
256− F.foldl' disjAdd bottom $
257− liftA2 S.union (S.toList xss) (S.toList yss)
258−
259−pattern BottomFormula :: JsonFormula t
260−pattern BottomFormula <-
261− DNF (S.null -> True)
262− where
263− BottomFormula = DNF S.empty
264−
265−isSingleton :: S.Set a -> Maybe a
266−isSingleton s
267− | S.size s == 1 = S.lookupMin s
268− | otherwise = Nothing
269−
270−pattern Conjunct :: [Condition t] -> S.Set (Condition t)
271−pattern Conjunct xs <-
272− (S.toList -> xs)
273− where
274− Conjunct = S.fromList
275−
276−{-# COMPLETE Conjunct #-}
277−
278−pattern SingleConjunct :: [Condition t] -> JsonFormula t
279−pattern SingleConjunct xs <-
280− DNF (isSingleton -> Just (Conjunct xs))
281− where
282− SingleConjunct xs = DNF $ S.singleton $ Conjunct xs
283−
284−pattern TopFormula :: JsonFormula t
285−pattern TopFormula <-
286− DNF (isSingleton -> Just (S.null -> True))
287− where
288− TopFormula = DNF $ S.singleton S.empty
289−
290−instance BoundedJoinSemiLattice (JsonFormula t) where
291− bottom = BottomFormula
292−
293−instance BoundedMeetSemiLattice (JsonFormula t) where
294− top = TopFormula
295−
296−foldLattice
297− :: BoundedLattice l
298− => (Condition t -> l)
299− -> JsonFormula t
300− -> l
301−foldLattice f (DNF xss) =
302− S.foldl'
303− (\z w ->
304− z \/ S.foldl' (\x y -> x /\ f y) top w)
305− bottom
306− xss
307−
308−satisfiesFormula :: TypedValue t -> JsonFormula t -> Bool
309−satisfiesFormula val = foldLattice (satisfiesTyped val)
310−
311−data ForeachType (f :: JsonType -> Type) = ForeachType
312− { forNull :: f 'Null
313− , forBoolean :: f 'Boolean
314− , forNumber :: f 'Number
315− , forString :: f 'String
316− , forArray :: f 'Array
317− , forObject :: f 'Object
318− }
319−
320−satisfies :: A.Value -> ForeachType JsonFormula -> Bool
321−satisfies val p = case val of
322− A.Null -> satisfiesFormula TNull $ forNull p
323− A.Bool b -> satisfiesFormula (TBool b) $ forBoolean p
324− A.Number n -> satisfiesFormula (TNumber n) $ forNumber p
325− A.String s -> satisfiesFormula (TString s) $ forString p
326− A.Array a -> satisfiesFormula (TArray a) $ forArray p
327− A.Object o -> satisfiesFormula (TObject o) $ forObject p
328−
329−deriving stock instance (forall x. Typeable x => Eq (f x)) => Eq (ForeachType f)
330−
331−deriving stock instance (forall x. Typeable x => Ord (f x)) => Ord (ForeachType f)
332−
333−deriving stock instance (forall x. Typeable x => Show (f x)) => Show (ForeachType f)
334−
335−foldType
336− :: Monoid m
337− => (forall x. Typeable x => JsonType -> (ForeachType f -> f x) -> m)
338− -> m
339−foldType k =
340− k Null forNull
341− <> k Boolean forBoolean
342− <> k Number forNumber
343− <> k String forString
344− <> k Array forArray
345− <> k Object forObject
346−
347−forType_
348− :: Applicative m
349− => (forall x. Typeable x => JsonType -> (ForeachType f -> f x) -> m ())
350− -> m ()
351−forType_ k = do
352− k Null forNull
353− k Boolean forBoolean
354− k Number forNumber
355− k String forString
356− k Array forArray
357− k Object forObject
358− pure ()
359−
360−instance (forall x. Lattice (f x)) => Lattice (ForeachType f) where
361− f1 \/ f2 =
362− ForeachType
363− { forNull = forNull f1 \/ forNull f2
364− , forBoolean = forBoolean f1 \/ forBoolean f2
365− , forNumber = forNumber f1 \/ forNumber f2
366− , forString = forString f1 \/ forString f2
367− , forArray = forArray f1 \/ forArray f2
368− , forObject = forObject f1 \/ forObject f2
369− }
370− f1 /\ f2 =
371− ForeachType
372− { forNull = forNull f1 /\ forNull f2
373− , forBoolean = forBoolean f1 /\ forBoolean f2
374− , forNumber = forNumber f1 /\ forNumber f2
375− , forString = forString f1 /\ forString f2
376− , forArray = forArray f1 /\ forArray f2
377− , forObject = forObject f1 /\ forObject f2
378− }
379−
380−instance
381− (forall x. BoundedJoinSemiLattice (f x))
382− => BoundedJoinSemiLattice (ForeachType f)
383− where
384− bottom =
385− ForeachType
386− { forNull = bottom
387− , forBoolean = bottom
388− , forNumber = bottom
389− , forString = bottom
390− , forArray = bottom
391− , forObject = bottom
392− }
393−
394−instance
395− (forall x. BoundedMeetSemiLattice (f x))
396− => BoundedMeetSemiLattice (ForeachType f)
397− where
398− top =
399− ForeachType
400− { forNull = top
401− , forBoolean = top
402− , forNumber = top
403− , forString = top
404− , forArray = top
405− , forObject = top
406− }
407−
408−instance Steppable Schema (Referenced Schema) where
409− data Step Schema (Referenced Schema)
410− = AllOfStep Int
411− | OneOfStep Int
412− | AnyOfStep Int
413− | ItemsObjectStep
414− | ItemsArrayStep Int
415− | AdditionalPropertiesStep
416− | NotStep
417− deriving (Eq, Ord, Show)
418−
419−instance Steppable Schema (Definitions (Referenced Schema)) where
420− data Step Schema (Definitions (Referenced Schema)) = PropertiesStep
421− deriving (Eq, Ord, Show)
422−
423−instance Steppable Schema Discriminator where
424− data Step Schema Discriminator = DiscriminatorStep
425− deriving (Eq, Ord, Show)
426−
427−instance Steppable Discriminator (Definitions (Referenced Schema)) where
428− data Step Discriminator (Definitions (Referenced Schema)) = DiscriminatorMapping
429− deriving (Eq, Ord, Show)
430−
431−parseDiscriminatorValue :: Text -> Referenced Schema
432−parseDiscriminatorValue v = case A.fromJSON @(Referenced Schema) $ A.object ["$ref" A..= v] of
433− A.Success x -> x
434− A.Error _ -> Ref $ Reference v
435−
436−-- | A fake writer monad that doesn't actually record anything and allows lazy recursion.
437−newtype Silent q f r a = Silent {runSilent :: a}
438− deriving stock (Functor)
439− deriving (Applicative, Monad) via Identity
440−
441−instance MonadWriter (P.PathsPrefixTree q f r) (Silent q f r) where
442− tell _ = Silent ()
443− listen (Silent x) = Silent (x, P.empty)
444− pass (Silent (x, _)) = Silent x
445−
446−instance MonadState (MemoState ()) (Silent q f r) where
447− get = Silent $ runIdentity $ runMemo () get
448− put _ = pure ()
449−
450−type MonadProcess m =
451− ( MonadReader (Traced (Definitions Schema)) m
452− , MonadWriter (P.PathsPrefixTree Behave AnIssue 'SchemaLevel) m
453− , MonadState (MemoState ()) m
454− )
455−
456−type SilentM = ReaderT (Traced (Definitions Schema)) (Silent Behave AnIssue 'SchemaLevel)
457−
458−warn :: MonadProcess m => Issue 'SchemaLevel -> m ()
459−warn issue = tell $ P.singleton $ AnItem Root $ AnIssue issue
460−
461−-- | Ignore warnings but allow a recursive loop that lazily computes a recursive 'Condition'.
462−silently :: MonadProcess m => SilentM a -> m a
463−silently m = do
464− defs <- R.ask
465− pure . runSilent $ runReaderT m defs
466−
467−warnKnot :: MonadProcess m => KnotTier (ForeachType JsonFormula) () m
468−warnKnot =
469− KnotTier
470− { onKnotFound = warn UnguardedRecursion
471− , onKnotUsed = \_ -> pure bottom
472− , tieKnot = \_ -> pure
473− }
474−
475−processRefSchema
476− :: MonadProcess m
477− => Traced (Referenced Schema)
478− -> m (ForeachType JsonFormula)
479−processRefSchema x = do
480− defs <- R.ask
481− memoWithKnot warnKnot (processSchema $ dereference defs x) (ask x)
482−
483−tracedAllOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
484−tracedAllOf sch =
485− _schemaAllOf (extract sch) <&> \xs ->
486− [traced (ask sch >>> step (AllOfStep i)) x | (i, x) <- zip [0 ..] xs]
487−
488−tracedAnyOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
489−tracedAnyOf sch =
490− _schemaAnyOf (extract sch) <&> \xs ->
491− [traced (ask sch >>> step (AnyOfStep i)) x | (i, x) <- zip [0 ..] xs]
492−
493−tracedOneOf :: Traced Schema -> Maybe [Traced (Referenced Schema)]
494−tracedOneOf sch =
495− _schemaOneOf (extract sch) <&> \xs ->
496− [traced (ask sch >>> step (OneOfStep i)) x | (i, x) <- zip [0 ..] xs]
497−
498−tracedItems :: Traced Schema -> Maybe (Either (Traced (Referenced Schema)) [Traced (Referenced Schema)])
499−tracedItems sch =
500− _schemaItems (extract sch) <&> \case
501− OpenApiItemsObject x -> Left $ traced (ask sch >>> step ItemsObjectStep) x
502− OpenApiItemsArray xs ->
503− Right
504− [traced (ask sch >>> step (ItemsArrayStep i)) x | (i, x) <- zip [0 ..] xs]
505−
506−tracedAdditionalProperties :: Traced Schema -> Maybe (Either Bool (Traced (Referenced Schema)))
507−tracedAdditionalProperties sch =
508− _schemaAdditionalProperties (extract sch) <&> \case
509− AdditionalPropertiesAllowed b -> Left b
510− AdditionalPropertiesSchema x -> Right $ traced (ask sch >>> step AdditionalPropertiesStep) x
511−
512−tracedDiscriminator :: Traced Schema -> Maybe (Traced Discriminator)
513−tracedDiscriminator = sequence . stepTraced DiscriminatorStep . fmap _schemaDiscriminator
514−
515−tracedProperties :: Traced Schema -> IOHM.InsOrdHashMap Text (Traced (Referenced Schema))
516−tracedProperties sch =
517− IOHM.mapWithKey
518− (\k -> traced (ask sch >>> step PropertiesStep >>> step (InsOrdHashMapKeyStep k)))
519− (_schemaProperties $ extract sch)
520−
521−-- | Turn a schema into a tuple of 'JsonFormula's that describes the condition
522−-- for every possible type of a JSON value. The conditions are independent, and
523−-- are thus checked independently.
524−processSchema
525− :: MonadProcess m
526− => Traced Schema
527− -> m (ForeachType JsonFormula)
528−processSchema sch@(extract -> Schema {..}) = do
529− let singletonFormula :: Condition t -> JsonFormula t
530− singletonFormula f = SingleConjunct [f]
531−
532− allClauses <- case tracedAllOf sch of
533− Nothing -> pure []
534− Just [] -> [] <$ warn (InvalidSchema "no items in allOf")
535− Just xs -> mapM processRefSchema xs
536−
537− anyClause <- case tracedAnyOf sch of
538− Nothing -> pure top
539− Just [] -> bottom <$ warn (InvalidSchema "no items in anyOf")
540− Just xs -> joins <$> mapM processRefSchema xs
541−
542− oneClause <- case tracedOneOf sch of
543− Nothing -> pure top
544− Just [] -> bottom <$ warn (InvalidSchema "no items in oneOf")
545− Just xs -> do
546− checkOneOfDisjoint xs >>= \case
547− True -> pure ()
548− False -> warn (NotSupported "Could not determine that oneOf branches are disjoint")
549− joins <$> mapM processRefSchema xs
550−
551− case _schemaNot of
552− Nothing -> pure ()
553− Just _ -> warn (NotSupported "not clause is unsupported")
554−
555− let typeClause = case _schemaType of
556− Nothing -> top
557− Just OpenApiNull ->
558− bottom
559− { forNull = top
560− }
561− Just OpenApiBoolean ->
562− bottom
563− { forBoolean = top
564− }
565− Just OpenApiNumber ->
566− bottom
567− { forNumber = top
568− }
569− Just OpenApiInteger ->
570− bottom
571− { forNumber = singletonFormula $ MultipleOf 1
572− }
573− Just OpenApiString ->
574− bottom
575− { forString = top
576− }
577− Just OpenApiArray ->
578− bottom
579− { forArray = top
580− }
581− Just OpenApiObject ->
582− bottom
583− { forObject = top
584− }
585−
586− let valueEnum A.Null =
587− bottom
588− { forNull = singletonFormula $ Exactly TNull
589− }
590− valueEnum (A.Bool b) =
591− bottom
592− { forBoolean = singletonFormula $ Exactly $ TBool b
593− }
594− valueEnum (A.Number n) =
595− bottom
596− { forNumber = singletonFormula $ Exactly $ TNumber n
597− }
598− valueEnum (A.String s) =
599− bottom
600− { forString = singletonFormula $ Exactly $ TString s
601− }
602− valueEnum (A.Array a) =
603− bottom
604− { forArray = singletonFormula $ Exactly $ TArray a
605− }
606− valueEnum (A.Object o) =
607− bottom
608− { forObject = singletonFormula $ Exactly $ TObject o
609− }
610− enumClause <- case _schemaEnum of
611− Nothing -> pure top
612− Just [] -> bottom <$ warn (InvalidSchema "no items in enum")
613− Just xs -> pure $ joins (valueEnum <$> xs)
614−
615− let maximumClause = case _schemaMaximum of
616− Nothing -> top
617− Just n ->
618− top
619− { forNumber = singletonFormula $
620− Maximum $
621− case _schemaExclusiveMaximum of
622− Just True -> Exclusive n
623− _ -> Inclusive n
624− }
625−
626− minimumClause = case _schemaMinimum of
627− Nothing -> top
628− Just n ->
629− top
630− { forNumber = singletonFormula $
631− Minimum $
632− Down $
633− case _schemaExclusiveMinimum of
634− Just True -> Exclusive $ Down n
635− _ -> Inclusive $ Down n
636− }
637−
638− multipleOfClause = case _schemaMultipleOf of
639− Nothing -> top
640− Just n ->
641− top
642− { forNumber = singletonFormula $ MultipleOf n
643− }
644−
645− formatClause <- case _schemaFormat of
646− Nothing -> pure top
647− Just f
648− | f `elem` ["int32", "int64", "float", "double"] ->
649− pure
650− top
651− { forNumber = singletonFormula $ NumberFormat f
652− }
653− Just f
654− | f `elem` ["byte", "binary", "date", "date-time", "password", "uuid"] ->
655− pure
656− top
657− { forString = singletonFormula $ StringFormat f
658− }
659− Just f -> top <$ warn (NotSupported $ "Unknown format: " <> f)
660−
661− let maxLengthClause = case _schemaMaxLength of
662− Nothing -> top
663− Just n ->
664− top
665− { forString = singletonFormula $ MaxLength n
666− }
667−
668− minLengthClause = case _schemaMinLength of
669− Nothing -> top
670− Just n ->
671− top
672− { forString = singletonFormula $ MinLength n
673− }
674−
675− patternClause = case _schemaPattern of
676− Nothing -> top
677− Just p ->
678− top
679− { forString = singletonFormula $ Pattern p
680− }
681−
682− itemsClause <- case tracedItems sch of
683− Nothing -> pure top
684− Just (Left rs) -> do
685− f <- silently $ processRefSchema rs
686− pure top {forArray = singletonFormula $ Items f rs}
687− Just (Right _) -> top <$ warn (NotSupported "array in items is not supported")
688−
689− let maxItemsClause = case _schemaMaxItems of
690− Nothing -> top
691− Just n ->
692− top
693− { forArray = singletonFormula $ MaxItems n
694− }
695−
696− minItemsClause = case _schemaMinItems of
697− Nothing -> top
698− Just n ->
699− top
700− { forArray = singletonFormula $ MinItems n
701− }
702−
703− uniqueItemsClause = case _schemaUniqueItems of
704− Just True ->
705− top
706− { forArray = singletonFormula UniqueItems
707− }
708− _ -> top
709−
710− (addProps, addPropSchema) <- case tracedAdditionalProperties sch of
711− Just (Right rs) -> (,Just rs) <$> silently (processRefSchema rs)
712− Just (Left False) -> pure (bottom, Nothing)
713− _ -> pure (top, Just $ traced (ask sch `Snoc` AdditionalPropertiesStep) $ Inline mempty)
714− propList <- forM (S.toList . S.fromList $ IOHM.keys _schemaProperties <> _schemaRequired) $ \k -> do
715− (f, psch) <- case IOHM.lookup k $ tracedProperties sch of
716− Just rs -> (,rs) <$> silently (processRefSchema rs)
717− Nothing ->
718− let fakeSchema = traced (ask sch `Snoc` AdditionalPropertiesStep) $ Inline mempty
719− in -- The mempty here is incorrect, but if addPropSchema was Nothing, then
720− -- addProps is bottom, and k is in _schemaRequired. We handle this situation
721− -- below and short-circuit the entire Properties condition to bottom
722− pure (addProps, fromMaybe fakeSchema addPropSchema)
723− pure (k, Property (k `elem` _schemaRequired) f psch)
724− let allBottom f = getAll $
725− foldType $ \_ ty -> case ty f of
726− BottomFormula -> All True
727− _ -> All False
728− allTop f = getAll $
729− foldType $ \_ ty -> case ty f of
730− TopFormula -> All True
731− _ -> All False
732− -- remove optional fields whose schemata match that of additional props
733− propMap = M.filter (\p -> propRequired p || propFormula p /= addProps) $ M.fromList propList
734− propertiesClause
735− | any (\p -> propRequired p && allBottom (propFormula p)) propMap =
736− bottom -- if any required field has unsatisfiable schema
737− | M.null propMap
738− , allTop addProps =
739− top -- if all fields are optional and have trivial schemata
740− | otherwise =
741− top
742− { forObject = singletonFormula $ Properties propMap addProps addPropSchema
743− }
744−
745− maxPropertiesClause = case _schemaMaxProperties of
746− Nothing -> top
747− Just n ->
748− top
749− { forObject = singletonFormula $ MaxProperties n
750− }
751−
752− minPropertiesClause = case _schemaMinProperties of
753− Nothing -> top
754− Just n ->
755− top
756− { forObject = singletonFormula $ MinProperties n
757− }
758−
759− nullableClause
760− | Just True <- _schemaNullable =
761− bottom
762− { forNull = singletonFormula $ Exactly TNull
763− }
764− | otherwise = bottom
765−
766− pure $
767− nullableClause
768− \/ meets
769− (allClauses
770− <> [ anyClause
771− , oneClause
772− , typeClause
773− , enumClause
774− , maximumClause
775− , minimumClause
776− , multipleOfClause
777− , formatClause
778− , maxLengthClause
779− , minLengthClause
780− , patternClause
781− , itemsClause
782− , maxItemsClause
783− , minItemsClause
784− , uniqueItemsClause
785− , propertiesClause
786− , maxPropertiesClause
787− , minPropertiesClause
788− ])
789−
790−{- TODO: ReadOnly/WriteOnly #68 -}
791−
792−checkOneOfDisjoint :: MonadProcess m => [Traced (Referenced Schema)] -> m Bool
793−checkOneOfDisjoint = const $ pure True -- TODO #69
794−
795−schemaToFormula
796− :: Traced (Definitions Schema)
797− -> Traced Schema
798− -> (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
799−schemaToFormula defs rs = runWriter . (`runReaderT` defs) . runMemo () $ processSchema rs
800−
801−checkFormulas
802− :: (HasAll (CheckEnv Schema) xs)
803− => HList xs
804− -> Behavior 'SchemaLevel
805− -> ProdCons (ForeachType JsonFormula, P.PathsPrefixTree Behave AnIssue 'SchemaLevel)
806− -> SemanticCompatFormula ()
807−checkFormulas env beh (ProdCons (fp, ep) (fc, ec)) =
808− case P.toList ep ++ P.toList ec of
809− issues@(_ : _) -> F.for_ issues $ \(AnItem t (AnIssue e)) -> issueAt (beh >>> t) e
810− [] -> do
811− -- We have the following isomorphisms:
812− -- (A ⊂ X ∪ Y) = (A ⊂ X) \/ (A ⊂ Y)
813− -- (A ⊂ X ∩ Y) = (A ⊂ X) /\ (A ⊂ Y)
814− -- (A ⊂ ⊤) = 1
815− -- (X ∪ Y ⊂ B) = (X ⊂ B) /\ (Y ⊂ B)
816− -- (∅ ⊂ B) = 1
817− -- The remaining cases are, notably, not isomorphisms:
818− -- 1) (A ⊂ ∅) <= 0
819− -- 2) (X ∩ Y ⊂ B) <= (X ⊂ B) \/ (Y ⊂ B)
820− -- 3) (⊤ ⊂ B) <= 0
821− -- Therefore we have the isomorphisms:
822− -- (⋃_i ⋂_j A[i,j]) ⊂ (⋃_k ⋂_l B[k,l])
823− -- = \/_k /\_l /\_i (⋂_j A[i,j]) ⊂ B[k,l]
824− -- = /\_i \/_k /\_l (⋂_j A[i,j]) ⊂ B[k,l]
825− -- with the caveat that the the set over which k ranges is nonempty.
826− -- This is because 1) is not an isomorphism.
827− -- Our disjunction loses information, so it makes sense to nest it as
828− -- deeply as possible, hence we choose the latter representation.
829− --
830− -- We delegate the verification of (⋂_j A[j]) ⊂ B to a separate heuristic
831− -- function, with the understanding that \/_j A[j] ⊂ B is a sufficient,
832− -- but not necessary condition (because of 2) and 3)).
833− --
834− -- If k ranges over an empty set, we have the isomorphism:
835− -- (⋃_i ⋂_j A[i,j]) ⊂ ∅ = /\_i (⋂_j A[i,j]) ⊂ ∅
836− -- where we again delegate (⋂_j A[j]) ⊂ ∅ to a heuristic, though here the
837− -- shortcut of \/_j A[j] ⊂ ∅ hardly helps.
838− forType_ $ \tyName ty -> do
839− let beh' = beh >>> step (OfType tyName)
840− case (ty fp, ty fc) of
841− (DNF pss, BottomFormula) -> F.for_ pss $ \(Conjunct ps) -> checkContradiction beh' ps
842− (DNF pss, SingleConjunct cs) -> F.for_ pss $ \(Conjunct ps) -> do
843− F.for_ cs $ checkImplication env beh' ps -- avoid disjuntion if there's only one conjunct
844− (DNF pss, DNF css) -> F.for_ pss $ \(Conjunct ps) -> do
845− anyOfAt
846− beh'
847− (NoMatchingCondition $ SomeCondition <$> ps)
848− [F.for_ cs $ checkImplication env beh' ps | Conjunct cs <- S.toList css]
849−
850−checkContradiction
851− :: Behavior 'TypedSchemaLevel
852− -> [Condition t]
853− -> SemanticCompatFormula ()
854−checkContradiction beh _ = issueAt beh NoContradiction -- TODO #70
855−
856−checkImplication
857− :: (HasAll (CheckEnv Schema) xs)
858− => HList xs
859− -> Behavior 'TypedSchemaLevel
860− -> [Condition t]
861− -> Condition t
862− -> SemanticCompatFormula ()
863−checkImplication env beh prods cons = case findExactly prods of
864− Just e
865− | all (satisfiesTyped e) prods ->
866− if satisfiesTyped e cons
867− then pure ()
868− else issueAt beh (EnumDoesntSatisfy $ untypeValue e)
869− | otherwise -> pure () -- vacuously true
870− Nothing -> case cons of
871− -- the above code didn't catch it, so there's no Exactly condition on the lhs
872− Exactly e -> issueAt beh (NoMatchingEnum $ untypeValue e)
873− Maximum m -> case findRelevant min (\case Maximum m' -> Just m'; _ -> Nothing) prods of
874− Just m' ->
875− if m' <= m
876− then pure ()
877− else issueAt beh (MatchingMaximumWeak $ ProdCons {producer = m', consumer = m})
878− Nothing -> issueAt beh (NoMatchingMaximum m)
879− Minimum m -> case findRelevant max (\case Minimum m' -> Just m'; _ -> Nothing) prods of
880− Just m' ->
881− if m' >= m
882− then pure ()
883− else issueAt beh (MatchingMinimumWeak ProdCons {producer = coerce m', consumer = coerce m})
884− Nothing -> issueAt beh (NoMatchingMinimum (coerce m))
885− MultipleOf m -> case findRelevant lcmScientific (\case MultipleOf m' -> Just m'; _ -> Nothing) prods of
886− Just m' ->
887− if lcmScientific m m' == m'
888− then pure ()
889− else issueAt beh (MatchingMultipleOfWeak $ ProdCons {producer = m', consumer = m})
890− Nothing -> issueAt beh (NoMatchingMultipleOf m)
891− NumberFormat f ->
892− if any (\case NumberFormat f' -> f == f'; _ -> False) prods
893− then pure ()
894− else issueAt beh (NoMatchingFormat f)
895− MaxLength m -> case findRelevant min (\case MaxLength m' -> Just m'; _ -> Nothing) prods of
896− Just m' ->
897− if m' <= m
898− then pure ()
899− else issueAt beh (MatchingMaxLengthWeak $ ProdCons {producer = m', consumer = m})
900− Nothing -> issueAt beh (NoMatchingMaxLength m)
901− MinLength m -> case findRelevant max (\case MinLength m' -> Just m'; _ -> Nothing) prods of
902− Just m' ->
903− if m' >= m
904− then pure ()
905− else issueAt beh (MatchingMinLengthWeak $ ProdCons {producer = m', consumer = m})
906− Nothing -> issueAt beh (NoMatchingMinLength m)
907− Pattern p ->
908− if any (\case Pattern p' -> p == p'; _ -> False) prods
909− then pure ()
910− else issueAt beh (NoMatchingPattern p) -- TODO: regex comparison #32
911− StringFormat f ->
912− if any (\case StringFormat f' -> f == f'; _ -> False) prods
913− then pure ()
914− else issueAt beh (NoMatchingFormat f)
915− Items _ cons' -> case findRelevant (<>) (\case Items _ rs -> Just (rs NE.:| []); _ -> Nothing) prods of
916− Just (rs NE.:| []) -> checkCompatibility env (beh >>> step InItems) $ ProdCons rs cons'
917− Just rs -> do
918− let sch = Inline mempty {_schemaAllOf = Just . NE.toList $ extract <$> rs}
919− checkCompatibility env (beh >>> step InItems) $ ProdCons (traced (ask $ NE.head rs) sch) cons' -- TODO: bad trace
920− Nothing -> issueAt beh NoMatchingItems
921− MaxItems m -> case findRelevant min (\case MaxItems m' -> Just m'; _ -> Nothing) prods of
922− Just m' ->
923− if m' <= m
924− then pure ()
925− else issueAt beh (MatchingMaxItemsWeak ProdCons {producer = m', consumer = m})
926− Nothing -> issueAt beh (NoMatchingMaxItems m)
927− MinItems m -> case findRelevant max (\case MinItems m' -> Just m'; _ -> Nothing) prods of
928− Just m' ->
929− if m' >= m
930− then pure ()
931− else issueAt beh (MatchingMinItemsWeak ProdCons {producer = m', consumer = m})
932− Nothing -> issueAt beh (NoMatchingMinItems m)
933− UniqueItems ->
934− if any (== UniqueItems) $ prods
935− then pure ()
936− else issueAt beh NoMatchingUniqueItems
937− Properties props _ madd -> case findRelevant (<>) (\case Properties props' _ madd' -> Just $ (props', madd') NE.:| []; _ -> Nothing) prods of
938− Just pm ->
939− anyOfAt beh NoMatchingProperties $
940− NE.toList pm <&> \(props', madd') -> do
941− F.for_ (S.fromList $ M.keys props <> M.keys props') $ \k -> do
942− let go sch sch' = checkCompatibility env (beh >>> step (InProperty k)) (ProdCons sch sch')
943− case (M.lookup k props', madd', M.lookup k props, madd) of
944− (Nothing, Nothing, _, _) -> pure () -- vacuously
945− (_, _, Nothing, Nothing) -> issueAt beh (UnexpectedProperty k)
946− (Just p', _, Just p, _) -> go (propRefSchema p') (propRefSchema p)
947− (Nothing, Just add', Just p, _) -> go add' (propRefSchema p)
948− (Just p', _, Nothing, Just add) -> go (propRefSchema p') add
949− (Nothing, Just _, Nothing, Just _) -> pure ()
950− case (maybe False propRequired $ M.lookup k props', maybe False propRequired $ M.lookup k props) of
951− (False, True) -> issueAt beh (PropertyNowRequired k)
952− _ -> pure ()
953− pure ()
954− case (madd', madd) of
955− (Nothing, _) -> pure () -- vacuously
956− (_, Nothing) -> issueAt beh NoAdditionalProperties
957− (Just add', Just add) -> checkCompatibility env (beh >>> step InAdditionalProperty) (ProdCons add' add)
958− pure ()
959− Nothing -> issueAt beh NoMatchingProperties
960− MaxProperties m -> case findRelevant min (\case MaxProperties m' -> Just m'; _ -> Nothing) prods of
961− Just m' ->
962− if m' <= m
963− then pure ()
964− else issueAt beh (MatchingMaxPropertiesWeak ProdCons {producer = m', consumer = m})
965− Nothing -> issueAt beh (NoMatchingMaxProperties m)
966− MinProperties m -> case findRelevant max (\case MinProperties m' -> Just m'; _ -> Nothing) prods of
967− Just m' ->
968− if m' >= m
969− then pure ()
970− else issueAt beh (MatchingMinPropertiesWeak ProdCons {producer = m', consumer = m})
971− Nothing -> issueAt beh (NoMatchingMinProperties m)
972− where
973− findExactly (Exactly x : _) = Just x
974− findExactly (_ : xs) = findExactly xs
975− findExactly [] = Nothing
976− findRelevant combine extr =
977− fmap (foldr1 combine) . NE.nonEmpty . mapMaybe extr
978− lcmScientific (toRational -> a) (toRational -> b) =
979− fromRational $ lcm (numerator a) (numerator b) % gcd (denominator a) (denominator b)
980−
981−instance Issuable 'TypedSchemaLevel where
982− data Issue 'TypedSchemaLevel
983− = -- | producer produces a specific value ($1), consumer has a condition that is not satisfied by said value
984− EnumDoesntSatisfy A.Value
985− | -- | consumer only expects a specific value which the producer does not produce.
986− NoMatchingEnum A.Value
987− | -- | consumer declares a maximum numeric value ($1), producer doesn't
988− NoMatchingMaximum (Bound Scientific)
989− | -- | consumer declares a maximum numeric value ($1), producer declares a weaker (higher) limit ($2)
990− MatchingMaximumWeak (ProdCons (Bound Scientific))
991− | -- | consumer declares a minimum numeric value, producer doesn't
992− NoMatchingMinimum (Bound Scientific)
993− | -- | consumer declares a minimum numeric value ($1), producer declares a weaker (lower) limit ($2)
994− MatchingMinimumWeak (ProdCons (Bound Scientific))
995− | -- | consumer declares that the numeric value must be a multiple of $1, producer doesn't
996− NoMatchingMultipleOf Scientific
997− | -- | consumer declares that the numeric value must be a multiple of $1, producer declares a weaker condition (multiple of $2)
998− MatchingMultipleOfWeak (ProdCons Scientific)
999− | -- | consumer declares a string/number format, producer declares none or a different format (TODO: improve via regex #32)
1000− NoMatchingFormat Format
1001− | -- | consumer declares a maximum length of the string ($1), producer doesn't.
1002− NoMatchingMaxLength Integer
1003− | -- | consumer declares a maximum length of the string ($1), producer declares a weaker (higher) limit ($2)
1004− MatchingMaxLengthWeak (ProdCons Integer)
1005− | -- | consumer declares a minimum length of the string ($1), producer doesn't.
1006− NoMatchingMinLength Integer
1007− | -- | consumer declares a minimum length of the string ($1), producer declares a weaker (lower) limit ($2)
1008− MatchingMinLengthWeak (ProdCons Integer)
1009− | -- | consumer declares the string value must matrix a regex ($1), producer doesn't declare or declares different regex (TODO: #32)
1010− NoMatchingPattern Pattern
1011− | -- | consumer declares the items of an array must satisfy some condition, producer doesn't
1012− NoMatchingItems
1013− | -- | consumer declares a maximum length of the array ($1), producer doesn't.
1014− NoMatchingMaxItems Integer
1015− | -- | consumer declares a maximum length of the array ($1), producer declares a weaker (higher) limit ($2)
1016− MatchingMaxItemsWeak (ProdCons Integer)
1017− | -- | consumer declares a minimum length of the array ($1), producer doesn't.
1018− NoMatchingMinItems Integer
1019− | -- | consumer declares a minimum length of the array ($1), producer declares a weaker (lower) limit ($2)
1020− MatchingMinItemsWeak (ProdCons Integer)
1021− | -- | consumer declares that items must be unique, producer doesn't
1022− NoMatchingUniqueItems
1023− | -- | consumer declares the properties of an object must satisfy some condition, producer doesn't
1024− NoMatchingProperties
1025− | -- | producer allows a property that is not allowed in the consumer
1026− UnexpectedProperty Text
1027− | -- | consumer requires a property that is not required/allowed in the producer
1028− PropertyNowRequired Text
1029− | -- | producer allows additional properties, consumer doesn't
1030− NoAdditionalProperties
1031− | -- | consumer declares a maximum number of properties in the object ($1), producer doesn't.
1032− NoMatchingMaxProperties Integer
1033− | -- | consumer declares a maximum number of properties in the object ($1), producer declares a weaker (higher) limit ($2)
1034− MatchingMaxPropertiesWeak (ProdCons Integer)
1035− | -- | consumer declares a minimum number of properties in the object ($1), producer doesn't.
1036− NoMatchingMinProperties Integer
1037− | -- | consumer declares a minimum number of properties in the object ($1), producer declares a weaker (lower) limit ($2)
1038− MatchingMinPropertiesWeak (ProdCons Integer)
1039− | -- | consumer declares that the value must satisfy a disjunction of some conditions, but producer's requirements couldn't be matched against any single one of them (TODO: split heuristic #71)
1040− NoMatchingCondition [SomeCondition]
1041− | -- | consumer indicates that values of this type are now allowed, but the producer does not do so (currently we only check immediate contradictions, c.f. #70)
1042− NoContradiction
1043− deriving stock (Eq, Ord, Show)
1044− issueIsUnsupported _ = False
1045− describeIssue (EnumDoesntSatisfy v) = para "The following enum value will yield an error:" <> showJSONValue v
1046− describeIssue (NoMatchingEnum v) = para "The following enum value is not supported:" <> showJSONValue v
1047− describeIssue (NoMatchingMaximum b) = para $ "Unexpected upper bound " <> showBound b <> "."
1048− describeIssue (MatchingMaximumWeak (ProdCons p c)) = para $ "Expected upper bound " <> showBound p <> " but but found " <> showBound c <> "."
1049− describeIssue (NoMatchingMinimum b) = para $ "Unexpected lower bound " <> showBound b <> "."
1050− describeIssue (MatchingMinimumWeak (ProdCons p c)) = para $ "Expected lower bound " <> showBound p <> " but but found " <> showBound c <> "."
1051− describeIssue (NoMatchingMultipleOf n) = para $ "Didn't expect the value to be a multiple of " <> show' n <> " but it was."
1052− describeIssue (MatchingMultipleOfWeak (ProdCons p c)) = para $ "Expected the value to be a multiple of " <> show' p <> " but found a multiple of " <> show' c <> "."
1053− describeIssue (NoMatchingFormat f) = para $ "Unexpected format: " <> code f <> "."
1054− describeIssue (NoMatchingMaxLength n) = para $ "Unexpected maximum length of the string " <> show' n <> "."
1055− describeIssue (MatchingMaxLengthWeak (ProdCons p c)) = para $ "Expected the maximum length of the string to be " <> show' p <> "but it was " <> show' c <> "."
1056− describeIssue (NoMatchingMinLength n) = para $ "Unexpected minimum length of the string " <> show' n <> "."
1057− describeIssue (MatchingMinLengthWeak (ProdCons p c)) = para $ "Expected the minimum length of the string to be " <> show' p <> "but it was " <> show' c <> "."
1058− describeIssue (NoMatchingPattern p) = para "Unexpected pattern (regular expression): " <> codeBlock p
1059− describeIssue NoMatchingItems = para "Couldn't find any matching items."
1060− describeIssue (NoMatchingMaxItems n) = para $ "Unexpected maximum length of the array " <> show' n <> "."
1061− describeIssue (MatchingMaxItemsWeak (ProdCons p c)) = para $ "Expected the maximum length of the array to be " <> show' p <> "but it was " <> show' c <> "."
1062− describeIssue (NoMatchingMinItems n) = para $ "Unexpected minimum length of the array " <> show' n <> "."
1063− describeIssue (MatchingMinItemsWeak (ProdCons p c)) = para $ "Expected the minimum length of the array to be " <> show' p <> "but it was " <> show' c <> "."
1064− describeIssue NoMatchingUniqueItems = para "Didn't expect the items to be unique, but they were."
1065− describeIssue NoMatchingProperties = para "Couldn't find matching properties."
1066− describeIssue (UnexpectedProperty p) = para $ "Expected the property " <> code p <> " to be allowed, but it wasn't."
1067− describeIssue (PropertyNowRequired p) = para $ "Don't have a required property " <> code p <> "."
1068− describeIssue NoAdditionalProperties = para "Expected additional properties to be allowed, but they weren't."
1069− describeIssue (NoMatchingMaxProperties n) = para $ "Unexpected maximum number of properties " <> show' n <> "."
1070− describeIssue (MatchingMaxPropertiesWeak (ProdCons p c)) = para $ "Expected the maximum number of properties to be " <> show' p <> "but it was " <> show' c <> "."
1071− describeIssue (NoMatchingMinProperties n) = para $ "Unexpected minimum number of properties " <> show' n <> "."
1072− describeIssue (MatchingMinPropertiesWeak (ProdCons p c)) = para $ "Expected the minimum number of properties to be " <> show' p <> "but it was " <> show' c <> "."
1073− describeIssue (NoMatchingCondition conds) =
1074− para "Expected the following conditions to hold, but they didn't:"
1075− <> bulletList ((\(SomeCondition c) -> showCondition c) <$> conds)
1076− describeIssue NoContradiction = para "Expected the type to be allowed, but it wasn't."
1077−
1078−showJSONValue :: A.Value -> Blocks
1079−showJSONValue v = codeBlockWith ("", ["json"], mempty) (T.decodeUtf8 . BSL.toStrict . A.encode $ v)
1080−
1081−showBound :: Show a => Bound a -> Inlines
1082−showBound (Inclusive x) = show' x <> " inclusive"
1083−showBound (Exclusive x) = show' x <> " exclusive"
1084−
1085−show' :: Show x => x -> Inlines
1086−show' = str . T.pack . show
1087−
1088−instance Issuable 'SchemaLevel where
1089− data Issue 'SchemaLevel
1090− = -- | Some (openapi-supported) feature that we do not support was encountered in the schema
1091− NotSupported Text
1092− | -- | The schema is actually invalid
1093− InvalidSchema Text
1094− | -- | The schema contains a reference loop along "anyOf"/"allOf"/"oneOf".
1095− UnguardedRecursion
1096− deriving stock (Eq, Ord, Show)
1097− issueIsUnsupported _ = True
1098−
1099− describeIssue (NotSupported i) =
1100− para (emph "Encountered a feature that OpenApi Diff does not support: " <> text i <> ".")
1101− describeIssue (InvalidSchema i) =
1102− para (emph "The schema is invalid: " <> text i <> ".")
1103− describeIssue UnguardedRecursion =
1104− para "Encountered recursion that is too complex for OpenApi Diff to untangle."
1105−
1106−instance Behavable 'SchemaLevel 'TypedSchemaLevel where
1107− data Behave 'SchemaLevel 'TypedSchemaLevel
1108− = OfType JsonType
1109− deriving stock (Eq, Ord, Show)
1110−
1111− describeBehaviour (OfType t) = describeJSONType t
1112−
1113−describeJSONType :: JsonType -> Inlines
1114−describeJSONType = \case
1115− Null -> "Null"
1116− Boolean -> "Boolean"
1117− Number -> "Number"
1118− String -> "String"
1119− Array -> "Array"
1120− Object -> "Object"
1121−
1122−instance Behavable 'TypedSchemaLevel 'SchemaLevel where
1123− data Behave 'TypedSchemaLevel 'SchemaLevel
1124− = InItems
1125− | InProperty Text
1126− | InAdditionalProperty
1127− deriving stock (Eq, Ord, Show)
1128−
1129− describeBehaviour InItems = "Items"
1130− describeBehaviour (InProperty p) = "Property " <> code p
1131− describeBehaviour InAdditionalProperty = "Additional properties"
1132−
1133−instance Subtree Schema where
1134− type SubtreeLevel Schema = 'SchemaLevel
1135− type CheckEnv Schema = '[ProdCons (Traced (Definitions Schema))]
1136− checkStructuralCompatibility env pc = do
1137− structuralEq $ fmap _schemaRequired <$> pc
1138− structuralEq $ fmap _schemaNullable <$> pc
1139− structuralMaybeWith (structuralList env) $ tracedAllOf <$> pc
1140− structuralMaybeWith (structuralList env) $ tracedOneOf <$> pc
1141− structuralMaybe env $ sequence . stepTraced NotStep . fmap _schemaNot <$> pc
1142− structuralMaybeWith (structuralList env) $ tracedAnyOf <$> pc
1143− iohmStructural env $ stepTraced PropertiesStep . fmap _schemaProperties <$> pc
1144− structuralMaybeWith structuralAdditionalProperties $ tracedAdditionalProperties <$> pc
1145− structuralMaybeWith structuralDiscriminator $ tracedDiscriminator <$> pc
1146− structuralEq $ fmap _schemaReadOnly <$> pc
1147− structuralEq $ fmap _schemaWriteOnly <$> pc
1148− structuralEq $ fmap _schemaXml <$> pc
1149− structuralEq $ fmap _schemaMaxProperties <$> pc
1150− structuralEq $ fmap _schemaMinProperties <$> pc
1151− structuralEq $ fmap _schemaDefault <$> pc
1152− structuralEq $ fmap _schemaType <$> pc
1153− structuralEq $ fmap _schemaFormat <$> pc
1154− structuralMaybeWith structuralItems $ tracedItems <$> pc
1155− structuralEq $ fmap _schemaMaximum <$> pc
1156− structuralEq $ fmap _schemaExclusiveMaximum <$> pc
1157− structuralEq $ fmap _schemaMinimum <$> pc
1158− structuralEq $ fmap _schemaExclusiveMinimum <$> pc
1159− structuralEq $ fmap _schemaMaxLength <$> pc
1160− structuralEq $ fmap _schemaMinLength <$> pc
1161− structuralEq $ fmap _schemaPattern <$> pc
1162− structuralEq $ fmap _schemaMaxItems <$> pc
1163− structuralEq $ fmap _schemaMinItems <$> pc
1164− structuralEq $ fmap _schemaUniqueItems <$> pc
1165− structuralEq $ fmap _schemaEnum <$> pc
1166− structuralEq $ fmap _schemaMultipleOf <$> pc
1167− pure ()
1168− where
1169− structuralAdditionalProperties
1170− (ProdCons (Left x) (Left y)) = unless (x == y) structuralIssue
1171− structuralAdditionalProperties
1172− (ProdCons (Right x) (Right y)) =
1173− checkSubstructure env $ ProdCons x y
1174− structuralAdditionalProperties _ = structuralIssue
1175− structuralDiscriminator pc' = do
1176− structuralEq $ fmap _discriminatorPropertyName <$> pc'
1177− iohmStructural env $
1178− stepTraced DiscriminatorMapping . fmap (fmap parseDiscriminatorValue . _discriminatorMapping) <$> pc'
1179− pure ()
1180− structuralItems (ProdCons (Left a) (Left b)) =
1181− checkSubstructure env $ ProdCons a b
1182− structuralItems (ProdCons (Right a) (Right b)) =
1183− structuralList env $ ProdCons a b
1184− structuralItems _ = structuralIssue
1185− checkSemanticCompatibility env beh schs = do
1186− let defs = getH env
1187− checkFormulas env beh $ schemaToFormula <$> defs <*> schs
src/OpenAPI/Checker/Validate/Sums.hsdeleted−24
@@ -1,24 +0,0 @@
1−module OpenAPI.Checker.Validate.Sums
2− ( checkSums
3− ) where
4−
5−import Data.Foldable
6−import Data.Map.Strict (Map)
7−import qualified Data.Map.Strict as M
8−import OpenAPI.Checker.Behavior
9−import OpenAPI.Checker.Subtree
10−import OpenAPI.Checker.Paths
11−
12−checkSums
13− :: (Ord k, Issuable l)
14− => Paths q r l
15− -> (k -> Issue l)
16− -> (k -> ProdCons t -> CompatFormula' q AnIssue r ())
17− -> ProdCons (Map k t)
18− -> CompatFormula' q AnIssue r ()
19−checkSums xs noElt check (ProdCons p c) = for_ (M.toList p) $ \(key, prodElt) ->
20− case M.lookup key c of
21− Nothing -> issueAt xs $ noElt key
22− Just consElt ->
23− let sumElts = ProdCons prodElt consElt
24− in check key sumElts
stack.yaml+23−1
@@ -1 +1,23 @@
1−resolver: nightly-2021-06-01
1+resolver: lts-22.34
2+
3+packages:
4+ - .
5+
6+extra-deps:
7+ - base16-bytestring-1.0.2.0
8+ - freer-simple-1.2.1.2
9+ - generics-sop-0.5.1.4
10+ - github-0.29
11+ - http-link-header-1.2.1
12+ - open-union-0.4.0.0
13+ - th-abstraction-0.7.0.0
14+ - type-fun-0.1.3
15+ - typerep-map-0.6.0.0
16+
17+# Required for freer-simple and typerep-map
18+allow-newer: true
19+
20+nix:
21+# packages: [pkg-config yq zlib]
22+ shell-file: ./nix/shell.nix
23+ pure: false
stack.yaml.lock+40−5
@@ -3,10 +3,45 @@
33# For more information, please see the documentation at:
44# https://docs.haskellstack.org/en/stable/lock_files
55
6−packages: []
6+packages:
7+- completed:
8+ hackage: open-union-0.4.0.0@sha256:1c8f8090054b0974e95e44bed88e74fff956ba2120aade6e8deea92d65ef5e49,3503
9+ pantry-tree:
10+ size: 329
11+ sha256: e01838ec41f7aa2a97aa2c3586c8188c4ad093ba0b2be41229ab7b8dbd33869e
12+ original:
13+ hackage: open-union-0.4.0.0
14+- completed:
15+ hackage: type-fun-0.1.3@sha256:336b851757792f201078043210aec180021ac052f0955c71fa330a5fe11b0604,1765
16+ pantry-tree:
17+ size: 583
18+ sha256: b977d42525f0b4223959918d18e7905085283e937493c395077b608cd19b42c1
19+ original:
20+ hackage: type-fun-0.1.3
21+- completed:
22+ hackage: github-0.26@sha256:a9d4046325c3eb28cdc7bef2c3f5bb213328caeae0b7dce6f51de655f0bffaa1,7162
23+ pantry-tree:
24+ size: 7511
25+ sha256: b71aab2984b268030c9e2617043575681134c1fe60dffbd5596e659c0a3e9aec
26+ original:
27+ hackage: github-0.26
28+- completed:
29+ hackage: base16-bytestring-0.1.1.7@sha256:0021256a9628971c08da95cb8f4d0d72192f3bb8a7b30b55c080562d17c43dd3,2231
30+ pantry-tree:
31+ size: 454
32+ sha256: 2dc99cd67293b09204098202d0bdcdcf89d2b8c69ce6c8f4e31deadbdab2a7f9
33+ original:
34+ hackage: base16-bytestring-0.1.1.7
35+- completed:
36+ hackage: http-link-header-1.0.3.1@sha256:9917c26635a46eff5d36c5344a4ae42fad2b5de79c0e300363bddd5eec66facd,1937
37+ pantry-tree:
38+ size: 990
39+ sha256: 155feaf856daf5b55491048c8c4726ba765a8fe79263ebdbfc82f6c385a15715
40+ original:
41+ hackage: http-link-header-1.0.3.1
742snapshots:
843- completed:
9− size: 587963
10− url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2021/6/1.yaml
11− sha256: 6f13285c82266d1d06f7f68366a5190dcbc6758ae8806813005cf56daa6bb9be
12− original: nightly-2021-06-01
44+ size: 587393
45+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/25.yaml
46+ sha256: 1b74fb5e970497b5aefae56703f1bd44aa648bd1a5ef95c1eb8c29775087e2bf
47+ original: lts-18.25
test/README.md+1−1
@@ -30,7 +30,7 @@ This test would read the files `a.yaml` and `b.yaml` using the `Yaml.decodeFileT
3030
3131## Supported feature tests
3232
33−If a test starts with either `x ` or `v `, the test is assumed to test the support of some OpenApi functionality. If the test begins `x ` it means that the feature is expected to be not supported, and the result will only be checked to have an "unsupported" flag set. If it starts with `v ` the test is expected to be supported and the result is compared to some file on disk.
33+If a test starts with either `x ` or `v `, the test is assumed to test the support of some OpenAPI functionality. If the test begins `x ` it means that the feature is expected to be not supported, and the result will only be checked to have an "unsupported" flag set. If it starts with `v ` the test is expected to be supported and the result is compared to some file on disk.
3434
3535The result will be reflected in the generated compatibility matrix.
3636
test/Spec.hs+1−1
@@ -9,4 +9,4 @@ main = defaultMain =<< tests
99tests :: IO TestTree
1010tests = do
1111 goldenReportTree <- Spec.Golden.TraceTree.tests
12− return . localOption (mkTimeout 1000000) $ goldenReportTree
12+ return . localOption (mkTimeout 5000000) $ goldenReportTree
test/Spec/Golden/Extra.hs+49−45
@@ -1,8 +1,8 @@
11module Spec.Golden.Extra
2− ( getGoldenInputs
3− , getGoldenInputsUniform
4− , goldenInputsTree
5− , goldenInputsTreeUniform
2+ ( getGoldenInputs,
3+ getGoldenInputsUniform,
4+ goldenInputsTree,
5+ goldenInputsTreeUniform,
66 )
77where
88
@@ -17,14 +17,14 @@ import Test.Tasty.Golden
1717data TestInput t
1818 = TestInputNode TestName [TestInput t]
1919 | TestInputLeaf TestName t FilePath
20− deriving (Functor)
20+ deriving stock (Functor)
2121
22−getGoldenInputs
23− :: (Each s t (FilePath, FilePath -> IO a) a)
24− => TestName
25− -> FilePath
26− -> s
27− -> IO (TestInput t)
22+getGoldenInputs ::
23+ (Each s t (FilePath, FilePath -> IO a) a) =>
24+ TestName ->
25+ FilePath ->
26+ s ->
27+ IO (TestInput t)
2828getGoldenInputs name filepath inp = do
2929 dirs' <- listDirectory filepath >>= filterM (doesDirectoryExist . (filepath </>))
3030 case dirs' of
@@ -39,51 +39,55 @@ getGoldenInputs name filepath inp = do
3939 TestInputNode name
4040 <$> forM dirs (\dir -> getGoldenInputs dir (filepath </> dir) inp)
4141
42−getGoldenInputsUniform
43− :: (Each t h (FilePath, FilePath -> IO a) a)
44− => (Each s t FilePath (FilePath, FilePath -> IO a))
45− => TestName
46− -> (FilePath -> IO a)
47− -> FilePath
48− -> s
49− -> IO (TestInput h)
42+getGoldenInputsUniform ::
43+ (Each t h (FilePath, FilePath -> IO a) a) =>
44+ (Each s t FilePath (FilePath, FilePath -> IO a)) =>
45+ TestName ->
46+ (FilePath -> IO a) ->
47+ FilePath ->
48+ s ->
49+ IO (TestInput h)
5050getGoldenInputsUniform name f filepath inp = getGoldenInputs name filepath $ inp & each %~ (,f)
5151
52−goldenInputsTree
53− :: (Each s t (FilePath, FilePath -> IO a) a)
54− => TestName
55− -> FilePath -- ^ Root path
56− -> FilePath -- ^ Name of golden file
57− -> s
58− -> (t -> IO BSL.ByteString)
59− -> IO TestTree
60−goldenInputsTree name filepath golden inp f = do
52+goldenInputsTree ::
53+ (Each s t (FilePath, FilePath -> IO a) a) =>
54+ TestName ->
55+ -- | Root path
56+ FilePath ->
57+ -- | Name of golden file
58+ FilePath ->
59+ s ->
60+ (t -> IO BSL.ByteString) ->
61+ IO TestTree
62+goldenInputsTree name filepath golden inp f =
6163 runTestInputTree golden f <$> getGoldenInputs name filepath inp
6264
63−runTestInputTree
64− :: FilePath
65− -> (t -> IO BSL.ByteString)
66− -> TestInput t
67− -> TestTree
65+runTestInputTree ::
66+ FilePath ->
67+ (t -> IO BSL.ByteString) ->
68+ TestInput t ->
69+ TestTree
6870runTestInputTree golden f (TestInputNode name rest) =
6971 testGroup name (runTestInputTree golden f <$> rest)
7072runTestInputTree golden f (TestInputLeaf name t path) =
7173 goldenVsStringDiff
7274 name
73− (\ref new -> ["diff", "-u", ref, new])
75+ (\ref new -> ["diff-yaml", ref, new])
7476 (path </> golden)
7577 (f t)
7678
77−goldenInputsTreeUniform
78− :: ( Each t h (FilePath, FilePath -> IO a) a
79− , Each s t FilePath (FilePath, FilePath -> IO a)
80− )
81− => String
82− -> FilePath -- ^ Root path
83− -> FilePath -- ^ Name of golden file
84− -> s
85− -> (FilePath -> IO a)
86− -> (h -> IO BSL.ByteString)
87− -> IO TestTree
79+goldenInputsTreeUniform ::
80+ ( Each t h (FilePath, FilePath -> IO a) a
81+ , Each s t FilePath (FilePath, FilePath -> IO a)
82+ ) =>
83+ String ->
84+ -- | Root path
85+ FilePath ->
86+ -- | Name of golden file
87+ FilePath ->
88+ s ->
89+ (FilePath -> IO a) ->
90+ (h -> IO BSL.ByteString) ->
91+ IO TestTree
8892goldenInputsTreeUniform name filepath golden inp h =
8993 goldenInputsTree name filepath golden (inp & each %~ (,h))
test/Spec/Golden/TraceTree.hs+8−21
@@ -1,5 +1,5 @@
11module Spec.Golden.TraceTree
2− ( tests
2+ ( tests,
33 )
44where
55
@@ -7,20 +7,16 @@ import Control.Category
77import Control.Exception
88import qualified Data.ByteString.Lazy as BSL
99import Data.Default
10−import Data.HList
11−import Data.OpenApi
10+import Data.OpenApi.Compare.Run
11+import Data.OpenApi.Compare.Validate.OpenApi ()
1212import Data.Text (Text)
1313import qualified Data.Text.Encoding as T
1414import qualified Data.Yaml as Yaml
15−import OpenAPI.Checker.Behavior
16−import OpenAPI.Checker.Paths
17−import OpenAPI.Checker.PathsPrefixTree
18−import OpenAPI.Checker.Report
19−import OpenAPI.Checker.Subtree
20−import OpenAPI.Checker.Validate.OpenApi ()
2115import Spec.Golden.Extra
2216import Test.Tasty (TestTree, testGroup)
17+import Text.Pandoc.Builder
2318import Text.Pandoc.Class
19+import Text.Pandoc.Options
2420import Text.Pandoc.Writers
2521import Prelude hiding (id, (.))
2622
@@ -29,7 +25,7 @@ tests = do
2925 traceTreeTests <-
3026 goldenInputsTreeUniform
3127 "TraceTree"
32− "test/golden/common"
28+ "test/golden"
3329 "trace-tree.yaml"
3430 ("a.yaml", "b.yaml")
3531 Yaml.decodeFileThrow
@@ -38,22 +34,13 @@ tests = do
3834 reportTests <-
3935 goldenInputsTreeUniform
4036 "Report"
41− "test/golden/common"
37+ "test/golden"
4238 "report.md"
4339 ("a.yaml", "b.yaml")
4440 Yaml.decodeFileThrow
45− (runPandoc . writeMarkdown def . generateReport . runChecker)
41+ (runPandoc . writeMarkdown def {writerExtensions = githubMarkdownExtensions} . doc . fst . runReport def)
4642
4743 return $ testGroup "Golden tests" [traceTreeTests, reportTests]
4844
4945runPandoc :: PandocPure Text -> IO BSL.ByteString
5046runPandoc = either throwIO (pure . BSL.fromStrict . T.encodeUtf8) . runPure
51−
52−runChecker :: (OpenApi, OpenApi) -> Either (PathsPrefixTree Behave AnIssue 'APILevel) ()
53−runChecker = runCompatFormula . checkCompatibility HNil Root . toPC
54− where
55− toPC (c, s) =
56− ProdCons
57− { producer = traced (step ClientSchema) c
58− , consumer = traced (step ServerSchema) s
59− }
test/golden/common/bad-oneof-unchanged/a.yamlnew file+39
@@ -0,0 +1,39 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ oneOf:
26+ - type: object
27+ required: ["tag", "prop_A"]
28+ properties:
29+ tag:
30+ enum: ["A"]
31+ prop_A:
32+ type: string
33+ - type: object
34+ required: ["tag", "prop_B"]
35+ properties:
36+ tag:
37+ enum: ["A"]
38+ prop_B:
39+ type: number
test/golden/common/bad-oneof-unchanged/b.yamlnew file+39
@@ -0,0 +1,39 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ oneOf:
26+ - type: object
27+ required: ["tag", "prop_B"]
28+ properties:
29+ tag:
30+ enum: ["A"]
31+ prop_B:
32+ type: number
33+ - type: object
34+ required: ["tag", "prop_A"]
35+ properties:
36+ tag:
37+ enum: ["A"]
38+ prop_A:
39+ type: string
test/golden/common/bad-oneof-unchanged/report.mdnew file+19
@@ -0,0 +1,19 @@
1+# Summary
2+
3+| ❌ Breaking changes | ⚠️ Non-breaking changes | [❓ Unsupported feature changes](#unsupported-changes) |
4+|---------------------|-------------------------|--------------------------------------------------------|
5+| 0 | 0 | 2 |
6+
7+# <span id="unsupported-changes"></span>❓ Unsupported feature changes
8+
9+## **POST** /test
10+
11+### ➡️☁️ JSON Request
12+
13+Could not deduce that `oneOf` cases don't overlap. Treating the `oneOf`
14+as an `anyOf`. Reported errors might not be accurate.
15+
16+### ⬅️☁️ JSON Response – 200
17+
18+Could not deduce that `oneOf` cases don't overlap. Treating the `oneOf`
19+as an `anyOf`. Reported errors might not be accurate.
test/golden/common/bad-oneof-unchanged/trace-tree.yamlnew file+18
@@ -0,0 +1,18 @@
1+forwardChanges:
2+ AtPath "/test":
3+ InOperation PostMethod:
4+ InRequest:
5+ InPayload:
6+ PayloadSchema: OneOfNotDisjoint
7+ WithStatusCode 200:
8+ ResponsePayload:
9+ PayloadSchema: OneOfNotDisjoint
10+backwardChanges:
11+ AtPath "/test":
12+ InOperation PostMethod:
13+ InRequest:
14+ InPayload:
15+ PayloadSchema: OneOfNotDisjoint
16+ WithStatusCode 200:
17+ ResponsePayload:
18+ PayloadSchema: OneOfNotDisjoint
test/golden/common/enum-added/a.yamlnew file+25
@@ -0,0 +1,25 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ enum: ["A", "B"]
test/golden/common/enum-added/b.yamlnew file+25
@@ -0,0 +1,25 @@
1+openapi: "3.0.0"
2+info:
3+ version: 1.0.0
4+ title: Test
5+servers:
6+ - url: http://localhost/
7+paths:
8+ /test:
9+ post:
10+ requestBody:
11+ content:
12+ application/json:
13+ schema:
14+ $ref: "#/components/schemas/Test"
15+ responses:
16+ '200':
17+ description: test
18+ content:
19+ application/json:
20+ schema:
21+ $ref: "#/components/schemas/Test"
22+components:
23+ schemas:
24+ Test:
25+ enum: ["A", "B", "C"]
test/golden/common/enum-added/report.mdnew file+33
@@ -0,0 +1,33 @@
1+# Summary
2+
3+| [❌ Breaking changes](#breaking-changes) | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|------------------------------------------|--------------------------------------------------|
5+| 1 | 1 |
6+
7+# <span id="breaking-changes"></span>❌ Breaking changes
8+
9+## **POST** /test
10+
11+### ⬅️☁️ JSON Response – 200
12+
13+#### `$(String)`
14+
15+The following enum value was added:
16+
17+``` json
18+"C"
19+```
20+
21+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
22+
23+## **POST** /test
24+
25+### ➡️☁️ JSON Request
26+
27+#### `$(String)`
28+
29+The following enum value was added:
30+
31+``` json
32+"C"
33+```
test/golden/common/enum-added/trace-tree.yamlnew file+14
@@ -0,0 +1,14 @@
1+forwardChanges:
2+ AtPath "/test":
3+ InOperation PostMethod:
4+ WithStatusCode 200:
5+ ResponsePayload:
6+ PayloadSchema:
7+ OfType String: EnumDoesntSatisfy (String "C")
8+backwardChanges:
9+ AtPath "/test":
10+ InOperation PostMethod:
11+ InRequest:
12+ InPayload:
13+ PayloadSchema:
14+ OfType String: EnumDoesntSatisfy (String "C")
test/golden/common/enum-anyof/report.md+5−1
@@ -1 +1,5 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | ⚠️ Non-breaking changes |
4+|---------------------|-------------------------|
5+| 0 | 0 |
test/golden/common/enum-anyof/trace-tree.yaml+2−1
@@ -1 +1,2 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges: {}
test/golden/common/id/report.md+5−1
@@ -1 +1,5 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | ⚠️ Non-breaking changes |
4+|---------------------|-------------------------|
5+| 0 | 0 |
test/golden/common/id/trace-tree.yaml+2−1
@@ -1 +1,2 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges: {}
test/golden/common/json/recursive/report.md+5−1
@@ -1 +1,5 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | ⚠️ Non-breaking changes |
4+|---------------------|-------------------------|
5+| 0 | 0 |
test/golden/common/json/recursive/trace-tree.yaml+2−1
@@ -1 +1,2 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges: {}
test/golden/common/maximum-lowered/report.md+22−4
@@ -1,7 +1,25 @@
1−# **POST** /test
1+# Summary
22
3−## JSON Request
3+| [❌ Breaking changes](#breaking-changes) | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|------------------------------------------|--------------------------------------------------|
5+| 1 | 1 |
46
5−### Number
7+# <span id="breaking-changes"></span>❌ Breaking changes
68
7−Expected upper bound 3.0 inclusive but but found 2.0 inclusive.
9+## **POST** /test
10+
11+### ➡️☁️ JSON Request
12+
13+#### `$(Number)`
14+
15+Upper bound changed from 3.0 inclusive to 2.0 inclusive.
16+
17+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
18+
19+## **POST** /test
20+
21+### ⬅️☁️ JSON Response – 200
22+
23+#### `$(Number)`
24+
25+Upper bound changed from 3.0 inclusive to 2.0 inclusive.
test/golden/common/maximum-lowered/trace-tree.yaml+9−1
@@ -1,4 +1,4 @@
1−Left:
1+forwardChanges:
22 AtPath "/test":
33 InOperation PostMethod:
44 InRequest:
@@ -6,3 +6,11 @@ Left:
66 PayloadSchema:
77 OfType Number: MatchingMaximumWeak (ProdCons {producer = Inclusive 3.0,
88 consumer = Inclusive 2.0})
9+backwardChanges:
10+ AtPath "/test":
11+ InOperation PostMethod:
12+ WithStatusCode 200:
13+ ResponsePayload:
14+ PayloadSchema:
15+ OfType Number: MatchingMaximumWeak (ProdCons {producer = Inclusive 3.0,
16+ consumer = Inclusive 2.0})
test/golden/common/pathItem/operation/parameters/allowEmptyValue/reset/report.md+11−3
@@ -1,5 +1,13 @@
1−# **POST** /test
1+# Summary
22
3−## Parameter test1
3+| [❌ Breaking changes](#breaking-changes) | ⚠️ Non-breaking changes |
4+|------------------------------------------|-------------------------|
5+| 1 | 0 |
46
5−Expected that an empty parameter is allowed, but it isn't.
7+# <span id="breaking-changes"></span>❌ Breaking changes
8+
9+## **POST** /test
10+
11+### Parameter test1
12+
13+The parameter can no longer be empty.
test/golden/common/pathItem/operation/parameters/allowEmptyValue/reset/trace-tree.yaml+2−1
@@ -1,4 +1,5 @@
1−Left:
1+forwardChanges:
22 AtPath "/test":
33 InOperation PostMethod:
44 InParam "test1": ParamEmptinessIncompatible
5+backwardChanges: {}
test/golden/common/pathItem/operation/parameters/allowEmptyValue/set/report.md+13−1
@@ -1 +1,13 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|---------------------|--------------------------------------------------|
5+| 0 | 1 |
6+
7+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
8+
9+## **POST** /test
10+
11+### Parameter test1
12+
13+The parameter can now be empty.
test/golden/common/pathItem/operation/parameters/allowEmptyValue/set/trace-tree.yaml+5−1
@@ -1 +1,5 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges:
3+ AtPath "/test":
4+ InOperation PostMethod:
5+ InParam "test1": ParamEmptinessIncompatible
test/golden/common/pathItem/operation/parameters/change/report.md+25−5
@@ -1,9 +1,29 @@
1−# **POST** /test
1+# Summary
22
3−## Parameter test
3+| [❌ Breaking changes](#breaking-changes) | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|------------------------------------------|--------------------------------------------------|
5+| 1 | 1 |
46
5−### JSON Schema
7+# <span id="breaking-changes"></span>❌ Breaking changes
68
7−#### String
9+## **POST** /test
810
9−Expected the type to be allowed, but it wasn't.
11+### Parameter test
12+
13+#### JSON Schema
14+
15+##### `$(String)`
16+
17+The type has been removed.
18+
19+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
20+
21+## **POST** /test
22+
23+### Parameter test
24+
25+#### JSON Schema
26+
27+##### `$(Number)`
28+
29+The type has been added.
test/golden/common/pathItem/operation/parameters/change/trace-tree.yaml+8−2
@@ -1,6 +1,12 @@
1−Left:
1+forwardChanges:
22 AtPath "/test":
33 InOperation PostMethod:
44 InParam "test":
55 InParamSchema:
6− OfType String: NoContradiction
6+ OfType String: TypeBecomesEmpty
7+backwardChanges:
8+ AtPath "/test":
9+ InOperation PostMethod:
10+ InParam "test":
11+ InParamSchema:
12+ OfType Number: TypeBecomesEmpty
test/golden/common/pathItem/operation/parameters/required/false/add/report.md+5−1
@@ -1 +1,5 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | ⚠️ Non-breaking changes |
4+|---------------------|-------------------------|
5+| 0 | 0 |
test/golden/common/pathItem/operation/parameters/required/false/add/trace-tree.yaml+2−1
@@ -1 +1,2 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges: {}
test/golden/common/pathItem/operation/parameters/required/false/del/report.md+5−1
@@ -1 +1,5 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | ⚠️ Non-breaking changes |
4+|---------------------|-------------------------|
5+| 0 | 0 |
test/golden/common/pathItem/operation/parameters/required/false/del/trace-tree.yaml+2−1
@@ -1 +1,2 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges: {}
test/golden/common/pathItem/operation/parameters/required/reset/report.md+13−1
@@ -1 +1,13 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|---------------------|--------------------------------------------------|
5+| 0 | 1 |
6+
7+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
8+
9+## **POST** /test
10+
11+### Parameter test1
12+
13+Parameter is no longer required.
test/golden/common/pathItem/operation/parameters/required/reset/trace-tree.yaml+5−1
@@ -1 +1,5 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges:
3+ AtPath "/test":
4+ InOperation PostMethod:
5+ InParam "test1": ParamRequired
test/golden/common/pathItem/operation/parameters/required/set/report.md+11−3
@@ -1,5 +1,13 @@
1−# **POST** /test
1+# Summary
22
3−## Parameter test1
3+| [❌ Breaking changes](#breaking-changes) | ⚠️ Non-breaking changes |
4+|------------------------------------------|-------------------------|
5+| 1 | 0 |
46
5−Expected the parameter to be optional, but it is required.
7+# <span id="breaking-changes"></span>❌ Breaking changes
8+
9+## **POST** /test
10+
11+### Parameter test1
12+
13+Parameter has become required.
test/golden/common/pathItem/operation/parameters/required/set/trace-tree.yaml+2−1
@@ -1,4 +1,5 @@
1−Left:
1+forwardChanges:
22 AtPath "/test":
33 InOperation PostMethod:
44 InParam "test1": ParamRequired
5+backwardChanges: {}
test/golden/common/pathItem/operation/parameters/required/true/add/report.md+10−2
@@ -1,3 +1,11 @@
1−# **POST** /test
1+# Summary
22
3−Parameter test2 is not supported.
3+| [❌ Breaking changes](#breaking-changes) | ⚠️ Non-breaking changes |
4+|------------------------------------------|-------------------------|
5+| 1 | 0 |
6+
7+# <span id="breaking-changes"></span>❌ Breaking changes
8+
9+## **POST** /test
10+
11+Parameter `test2` has become required.
test/golden/common/pathItem/operation/parameters/required/true/add/trace-tree.yaml+2−1
@@ -1,3 +1,4 @@
1−Left:
1+forwardChanges:
22 AtPath "/test":
33 InOperation PostMethod: ParamNotMatched "test2"
4+backwardChanges: {}
test/golden/common/pathItem/operation/parameters/required/true/del/report.md+11−1
@@ -1 +1,11 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|---------------------|--------------------------------------------------|
5+| 0 | 1 |
6+
7+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
8+
9+## **POST** /test
10+
11+Parameter `test2` is no longer required.
test/golden/common/pathItem/operation/parameters/required/true/del/trace-tree.yaml+4−1
@@ -1 +1,4 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges:
3+ AtPath "/test":
4+ InOperation PostMethod: ParamNotMatched "test2"
test/golden/common/pathItem/operation/requestBody/mediaTypeObject/add/report.md+13−1
@@ -1 +1,13 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|---------------------|--------------------------------------------------|
5+| 0 | 1 |
6+
7+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
8+
9+## **POST** /test
10+
11+### Request
12+
13+Media type `application/x-www-form-urlencoded` has been added.
test/golden/common/pathItem/operation/requestBody/mediaTypeObject/add/trace-tree.yaml+5−1
@@ -1 +1,5 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges:
3+ AtPath "/test":
4+ InOperation PostMethod:
5+ InRequest: RequestMediaTypeNotFound application/x-www-form-urlencoded
test/golden/common/pathItem/operation/requestBody/mediaTypeObject/change/report.md+22−4
@@ -1,7 +1,25 @@
1−# **POST** /test
1+# Summary
22
3−## JSON Request
3+| [❌ Breaking changes](#breaking-changes) | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|------------------------------------------|--------------------------------------------------|
5+| 1 | 1 |
46
5−### String
7+# <span id="breaking-changes"></span>❌ Breaking changes
68
7−Expected the type to be allowed, but it wasn't.
9+## **POST** /test
10+
11+### ➡️☁️ JSON Request
12+
13+#### `$(String)`
14+
15+The type has been removed.
16+
17+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
18+
19+## **POST** /test
20+
21+### ➡️☁️ JSON Request
22+
23+#### `$(Number)`
24+
25+The type has been added.
test/golden/common/pathItem/operation/requestBody/mediaTypeObject/change/trace-tree.yaml+9−2
@@ -1,7 +1,14 @@
1−Left:
1+forwardChanges:
22 AtPath "/test":
33 InOperation PostMethod:
44 InRequest:
55 InPayload:
66 PayloadSchema:
7− OfType String: NoContradiction
7+ OfType String: TypeBecomesEmpty
8+backwardChanges:
9+ AtPath "/test":
10+ InOperation PostMethod:
11+ InRequest:
12+ InPayload:
13+ PayloadSchema:
14+ OfType Number: TypeBecomesEmpty
test/golden/common/pathItem/operation/requestBody/mediaTypeObject/del/report.md+11−4
@@ -1,6 +1,13 @@
1−# **POST** /test
1+# Summary
22
3−## Request
3+| [❌ Breaking changes](#breaking-changes) | ⚠️ Non-breaking changes |
4+|------------------------------------------|-------------------------|
5+| 1 | 0 |
46
5−Couldn't find a request body for media type
6−`application/x-www-form-urlencoded`.
7+# <span id="breaking-changes"></span>❌ Breaking changes
8+
9+## **POST** /test
10+
11+### Request
12+
13+Media type `application/x-www-form-urlencoded` has been removed.
test/golden/common/pathItem/operation/requestBody/mediaTypeObject/del/trace-tree.yaml+2−1
@@ -1,4 +1,5 @@
1−Left:
1+forwardChanges:
22 AtPath "/test":
33 InOperation PostMethod:
44 InRequest: RequestMediaTypeNotFound application/x-www-form-urlencoded
5+backwardChanges: {}
test/golden/common/pathItem/operation/requestBody/required/reset/report.md+13−1
@@ -1 +1,13 @@
1−# No breaking changes found ✨
1+# Summary
2+
3+| ❌ Breaking changes | [⚠️ Non-breaking changes](#non-breaking-changes) |
4+|---------------------|--------------------------------------------------|
5+| 0 | 1 |
6+
7+# <span id="non-breaking-changes"></span>⚠️ Non-breaking changes
8+
9+## **POST** /test
10+
11+### Request
12+
13+Request body is no longer required.
test/golden/common/pathItem/operation/requestBody/required/reset/trace-tree.yaml+5−1
@@ -1 +1,5 @@
1−Right: []
1+forwardChanges: {}
2+backwardChanges:
3+ AtPath "/test":
4+ InOperation PostMethod:
5+ InRequest: RequestBodyRequired
test/golden/common/pathItem/operation/requestBody/required/set/report.md+11−3
@@ -1,5 +1,13 @@
1−# **POST** /test
1+# Summary
22
3−## Request
3+| [❌ Breaking changes](#breaking-changes) | ⚠️ Non-breaking changes |
4+|------------------------------------------|-------------------------|
5+| 1 | 0 |
46
5−Expected the request body to be optional, but found it to be required.
7+# <span id="breaking-changes"></span>❌ Breaking changes
8+
9+## **POST** /test
10+
11+### Request
12+
13+Request body has become required.
test/golden/common/pathItem/operation/requestBody/required/set/trace-tree.yaml+2−1
@@ -1,4 +1,5 @@
1−Left:
1+forwardChanges:
22 AtPath "/test":
33 InOperation PostMethod:
44 InRequest: RequestBodyRequired
5+backwardChanges: {}
test/golden/common/pathItem/operation/responses/add/report.md+10−2

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/add/trace-tree.yaml+3−2

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/headers/mandatory/add/report.md+13−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/headers/mandatory/add/trace-tree.yaml+5−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/headers/mandatory/del/report.md+11−3

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/headers/mandatory/del/trace-tree.yaml+3−2

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/headers/optional/add/report.md+5−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/headers/optional/add/trace-tree.yaml+2−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/headers/optional/del/report.md+5−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/headers/optional/del/trace-tree.yaml+2−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/mediaTypeObject/add/report.md+11−4

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/mediaTypeObject/add/trace-tree.yaml+3−2

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/mediaTypeObject/change/report.md+22−4

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/mediaTypeObject/change/trace-tree.yaml+9−2

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/mediaTypeObject/del/report.md+13−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/change/mediaTypeObject/del/trace-tree.yaml+5−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/del/report.md+11−1

This diff is too big to show here.

test/golden/common/pathItem/operation/responses/del/trace-tree.yaml+4−1

This diff is too big to show here.

test/golden/common/property-removed-additional/a.yamlnew file+32

This diff is too big to show here.

test/golden/common/property-removed-additional/b.yamlnew file+29

This diff is too big to show here.

test/golden/common/property-removed-additional/report.mdnew file+39

This diff is too big to show here.

test/golden/common/property-removed-additional/trace-tree.yamlnew file+22

This diff is too big to show here.

test/golden/common/property-removed/report.md+15−7

This diff is too big to show here.

test/golden/common/property-removed/trace-tree.yaml+18−3

This diff is too big to show here.

test/golden/common/property-required/report.md+22−4

This diff is too big to show here.

test/golden/common/property-required/trace-tree.yaml+11−2

This diff is too big to show here.

test/golden/common/random-example/a.yamlnew file+56

This diff is too big to show here.

test/golden/common/random-example/b.yamlnew file+58

This diff is too big to show here.

test/golden/common/random-example/report.mdnew file+71

This diff is too big to show here.

test/golden/common/random-example/trace-tree.yamlnew file+48

This diff is too big to show here.

test/golden/common/recursive/a.yaml+6

This diff is too big to show here.

test/golden/common/recursive/b.yaml+6

This diff is too big to show here.

test/golden/common/recursive/report.md+33−1

This diff is too big to show here.

test/golden/common/recursive/trace-tree.yaml+26−1

This diff is too big to show here.

test/golden/common/security-scheme/report.md+26−8

This diff is too big to show here.

test/golden/common/security-scheme/trace-tree.yaml+6−1

This diff is too big to show here.

test/golden/common/servers/report.md+22−6

This diff is too big to show here.

test/golden/common/servers/trace-tree.yaml+6−1

This diff is too big to show here.

test/golden/common/tuple-items/heterogeneous-component-mismatch/a.yamlnew file+28

This diff is too big to show here.

test/golden/common/tuple-items/heterogeneous-component-mismatch/b.yamlnew file+28

This diff is too big to show here.

test/golden/common/tuple-items/heterogeneous-component-mismatch/report.mdnew file+37

This diff is too big to show here.

test/golden/common/tuple-items/heterogeneous-component-mismatch/trace-tree.yamlnew file+30

This diff is too big to show here.

test/golden/common/tuple-items/heterogeneous-length-mismatch/a.yamlnew file+29

This diff is too big to show here.

test/golden/common/tuple-items/heterogeneous-length-mismatch/b.yamlnew file+28

This diff is too big to show here.

test/golden/common/tuple-items/heterogeneous-length-mismatch/report.mdnew file+21

This diff is too big to show here.

test/golden/common/tuple-items/heterogeneous-length-mismatch/trace-tree.yamlnew file+26

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-component-mismatch/a.yamlnew file+28

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-component-mismatch/b.yamlnew file+29

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-component-mismatch/report.mdnew file+45

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-component-mismatch/trace-tree.yamlnew file+34

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-length-mismatch/a.yamlnew file+56

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-length-mismatch/b.yamlnew file+67

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-length-mismatch/report.mdnew file+73

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-length-mismatch/trace-tree.yamlnew file+52

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-vector/a.yamlnew file+28

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-vector/b.yamlnew file+29

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-vector/report.mdnew file+5

This diff is too big to show here.

test/golden/common/tuple-items/homogeneous-vector/trace-tree.yamlnew file+2

This diff is too big to show here.

test/golden/common/type-changing/a.yamlnew file+113

This diff is too big to show here.

test/golden/common/type-changing/b.yamlnew file+108

This diff is too big to show here.

test/golden/common/type-changing/report.mdnew file+105

This diff is too big to show here.

test/golden/common/type-changing/trace-tree.yamlnew file+60

This diff is too big to show here.

test/golden/common/unguarded-recursive/a.yaml → test/golden/common/unguarded-recursive/basic/a.yamlrenamed

The content is the same.

test/golden/common/unguarded-recursive/b.yaml → test/golden/common/unguarded-recursive/basic/b.yamlrenamed

The content is the same.

test/golden/common/unguarded-recursive/basic/report.mdnew file+13

This diff is too big to show here.

test/golden/common/unguarded-recursive/basic/trace-tree.yamlnew file+12

This diff is too big to show here.

test/golden/common/unguarded-recursive/report.mddeleted−5

This diff is too big to show here.

test/golden/common/unguarded-recursive/silent/a.yamlnew file+25

This diff is too big to show here.

test/golden/common/unguarded-recursive/silent/b.yamlnew file+19

This diff is too big to show here.

test/golden/common/unguarded-recursive/silent/report.mdnew file+15

This diff is too big to show here.

test/golden/common/unguarded-recursive/silent/trace-tree.yamlnew file+16

This diff is too big to show here.

test/golden/common/unguarded-recursive/trace-tree.yamldeleted−6

This diff is too big to show here.

test/golden/common/variant-added/a.yamlnew file+39

This diff is too big to show here.

test/golden/common/variant-added/b.yamlnew file+46

This diff is too big to show here.

test/golden/common/variant-added/report.mdnew file+25

This diff is too big to show here.

test/golden/common/variant-added/trace-tree.yamlnew file+16

This diff is too big to show here.

test/golden/common/variant-changed/a.yamlnew file+39

This diff is too big to show here.

test/golden/common/variant-changed/b.yamlnew file+39

This diff is too big to show here.

test/golden/common/variant-changed/report.mdnew file+45

This diff is too big to show here.

test/golden/common/variant-changed/trace-tree.yamlnew file+34

This diff is too big to show here.

test/golden/common/variant-deep-changed/a.yamlnew file+47

This diff is too big to show here.

test/golden/common/variant-deep-changed/b.yamlnew file+47

This diff is too big to show here.

test/golden/common/variant-deep-changed/report.mdnew file+45

This diff is too big to show here.

test/golden/common/variant-deep-changed/trace-tree.yamlnew file+34

This diff is too big to show here.