[chore] Bump go swagger (#2871)

* bump go swagger version

* bump swagger version
This commit is contained in:
tobi 2024-04-26 11:31:10 +02:00 committed by GitHub
parent 3a369d834a
commit fd8a724e77
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
251 changed files with 10841 additions and 11896 deletions

View file

@ -80,7 +80,7 @@ steps:
- yarn --cwd ./web/source build - yarn --cwd ./web/source build
- name: snapshot - name: snapshot
image: superseriousbusiness/gotosocial-drone-build:0.5.0 # https://github.com/superseriousbusiness/gotosocial-drone-build image: superseriousbusiness/gotosocial-drone-build:0.6.0 # https://github.com/superseriousbusiness/gotosocial-drone-build
volumes: volumes:
- name: go-build-cache - name: go-build-cache
path: /root/.cache/go-build path: /root/.cache/go-build
@ -121,7 +121,7 @@ steps:
- main - main
- name: release - name: release
image: superseriousbusiness/gotosocial-drone-build:0.5.0 # https://github.com/superseriousbusiness/gotosocial-drone-build image: superseriousbusiness/gotosocial-drone-build:0.6.0 # https://github.com/superseriousbusiness/gotosocial-drone-build
volumes: volumes:
- name: go-build-cache - name: go-build-cache
path: /root/.cache/go-build path: /root/.cache/go-build
@ -180,7 +180,7 @@ clone:
steps: steps:
- name: mirror - name: mirror
image: superseriousbusiness/gotosocial-drone-build:0.5.0 image: superseriousbusiness/gotosocial-drone-build:0.6.0
environment: environment:
ORIGIN_REPO: https://github.com/superseriousbusiness/gotosocial ORIGIN_REPO: https://github.com/superseriousbusiness/gotosocial
TARGET_REPO: https://codeberg.org/superseriousbusiness/gotosocial TARGET_REPO: https://codeberg.org/superseriousbusiness/gotosocial
@ -193,6 +193,6 @@ steps:
--- ---
kind: signature kind: signature
hmac: f7ef1e0d3d4fe0a55d43ba0ab5ed6cb5f5c8bf00791464ce7b251a3cdbfd954a hmac: 643cd740e2b7bcb39d7093d34f04863b5907efb72f2db8912337389df4ad9f0f
... ...

40
go.mod
View file

@ -34,7 +34,7 @@ require (
github.com/gin-contrib/sessions v1.0.0 github.com/gin-contrib/sessions v1.0.0
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/go-playground/form/v4 v4.2.1 github.com/go-playground/form/v4 v4.2.1
github.com/go-swagger/go-swagger v0.30.5 github.com/go-swagger/go-swagger v0.30.6-0.20240418033037-c46c303aaa02
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.1.2 github.com/gorilla/feeds v1.1.2
github.com/gorilla/websocket v1.5.1 github.com/gorilla/websocket v1.5.1
@ -89,7 +89,7 @@ require (
codeberg.org/gruf/go-mangler v1.3.0 // indirect codeberg.org/gruf/go-mangler v1.3.0 // indirect
codeberg.org/gruf/go-maps v1.0.3 // indirect codeberg.org/gruf/go-maps v1.0.3 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aymerick/douceur v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect
@ -111,7 +111,7 @@ require (
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e // indirect github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
@ -120,17 +120,17 @@ require (
github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.20.4 // indirect github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect github.com/go-openapi/inflect v0.21.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/loads v0.21.2 // indirect github.com/go-openapi/loads v0.22.0 // indirect
github.com/go-openapi/runtime v0.26.0 // indirect github.com/go-openapi/runtime v0.28.0 // indirect
github.com/go-openapi/spec v0.20.9 // indirect github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/strfmt v0.21.7 // indirect github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.22.4 // indirect github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/validate v0.22.1 // indirect github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.19.0 // indirect github.com/go-playground/validator/v10 v10.19.0 // indirect
@ -141,14 +141,14 @@ require (
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
github.com/gorilla/context v1.1.2 // indirect github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/css v1.0.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/sessions v1.2.2 // indirect github.com/gorilla/sessions v1.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
@ -183,11 +183,11 @@ require (
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/xid v1.5.0 // indirect github.com/rs/xid v1.5.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect github.com/spf13/afero v1.11.0 // indirect
@ -209,7 +209,7 @@ require (
go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.7.0 // indirect golang.org/x/arch v0.7.0 // indirect
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.16.0 // indirect golang.org/x/mod v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.19.0 // indirect golang.org/x/sys v0.19.0 // indirect

189
go.sum
View file

@ -85,12 +85,11 @@ github.com/KimMachineGun/automemlimit v0.6.0 h1:p/BXkH+K40Hax+PuWWPQ478hPjsp9h1C
github.com/KimMachineGun/automemlimit v0.6.0/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY= github.com/KimMachineGun/automemlimit v0.6.0/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/abema/go-mp4 v1.2.0 h1:gi4X8xg/m179N/J15Fn5ugywN9vtI6PLk6iLldHGLAk= github.com/abema/go-mp4 v1.2.0 h1:gi4X8xg/m179N/J15Fn5ugywN9vtI6PLk6iLldHGLAk=
github.com/abema/go-mp4 v1.2.0/go.mod h1:vPl9t5ZK7K0x68jh12/+ECWBCXoWuIDtNgPtU2f04ws= github.com/abema/go-mp4 v1.2.0/go.mod h1:vPl9t5ZK7K0x68jh12/+ECWBCXoWuIDtNgPtU2f04ws=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
@ -98,7 +97,6 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
@ -176,9 +174,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@ -218,46 +215,28 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk=
github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw=
github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8=
github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k=
github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU=
github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@ -270,39 +249,12 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91
github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-swagger/go-swagger v0.30.6-0.20240418033037-c46c303aaa02 h1:J6YiT/eg3gAfKMdVCkWXe6khsO+nxa8W4URZ4AUqzbA=
github.com/go-swagger/go-swagger v0.30.5 h1:SQ2+xSonWjjoEMOV5tcOnZJVlfyUfCBhGQGArS1b9+U= github.com/go-swagger/go-swagger v0.30.6-0.20240418033037-c46c303aaa02/go.mod h1:i1/E+d8iPNReSE7y04FaVu5OPKB3il5cn+T1Egogg3I=
github.com/go-swagger/go-swagger v0.30.5/go.mod h1:cWUhSyCNqV7J1wkkxfr5QmbcnCewetCdvEXqgPvbc/Q=
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0=
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-xmlfmt/xmlfmt v0.0.0-20211206191508-7fd73a941850 h1:PSPmmucxGiFBtbQcttHTUc4LQ3P09AW+ldO2qspyKdY= github.com/go-xmlfmt/xmlfmt v0.0.0-20211206191508-7fd73a941850 h1:PSPmmucxGiFBtbQcttHTUc4LQ3P09AW+ldO2qspyKdY=
github.com/go-xmlfmt/xmlfmt v0.0.0-20211206191508-7fd73a941850/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-xmlfmt/xmlfmt v0.0.0-20211206191508-7fd73a941850/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
@ -342,7 +294,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -352,7 +303,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
@ -386,8 +336,8 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw= github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw=
github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y= github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
@ -406,15 +356,15 @@ github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
@ -430,7 +380,6 @@ github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LF
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@ -440,12 +389,9 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@ -453,10 +399,7 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -468,13 +411,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@ -498,8 +436,6 @@ github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa1
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
@ -510,12 +446,10 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@ -530,12 +464,9 @@ github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e h1:s2RNOM/IGd
github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e/go.mod h1:nBdnFKj15wFbf94Rwfq4m30eAcyY9V/IyKAGQFtqkW0= github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e/go.mod h1:nBdnFKj15wFbf94Rwfq4m30eAcyY9V/IyKAGQFtqkW0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -556,12 +487,10 @@ github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg= github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@ -572,11 +501,9 @@ github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWR
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
@ -590,16 +517,13 @@ github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNo
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
@ -691,11 +615,6 @@ github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSV
github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ= github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
@ -704,7 +623,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
@ -718,9 +636,6 @@ github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U=
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.29.8-concurrency-workaround h1:ESobxED9bfE0nOQP/WPv9+tMR8oZoDIWRKlNK2Vs4Ms= gitlab.com/NyaaaWhatsUpDoc/sqlite v1.29.8-concurrency-workaround h1:ESobxED9bfE0nOQP/WPv9+tMR8oZoDIWRKlNK2Vs4Ms=
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.29.8-concurrency-workaround/go.mod h1:lQPm27iqa4UNZpmr4Aor0MH0HkCLbt1huYDfWylLZFk= gitlab.com/NyaaaWhatsUpDoc/sqlite v1.29.8-concurrency-workaround/go.mod h1:lQPm27iqa4UNZpmr4Aor0MH0HkCLbt1huYDfWylLZFk=
go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@ -757,16 +672,12 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
@ -780,8 +691,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -838,8 +749,6 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
@ -856,27 +765,20 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -903,8 +805,6 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -924,8 +824,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
@ -940,13 +838,9 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@ -1071,7 +965,6 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@ -1091,9 +984,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -5,12 +5,9 @@ linters:
disable-all: true disable-all: true
enable: enable:
- misspell - misspell
- structcheck
- govet - govet
- staticcheck - staticcheck
- deadcode
- errcheck - errcheck
- varcheck
- unparam - unparam
- ineffassign - ineffassign
- nakedret - nakedret

View file

@ -1,7 +1,5 @@
GOPATH=$(shell go env GOPATH) GOPATH=$(shell go env GOPATH)
GOLANGCI_LINT=$(GOPATH)/bin/golangci-lint GOLANGCI_LINT=$(GOPATH)/bin/golangci-lint
GOFUZZBUILD = $(GOPATH)/bin/go-fuzz-build
GOFUZZ = $(GOPATH)/bin/go-fuzz
.PHONY: lint .PHONY: lint
lint: $(GOLANGCI_LINT) lint: $(GOLANGCI_LINT)
@ -19,19 +17,14 @@ test-cover:
GO111MODULE=on go test -cover . GO111MODULE=on go test -cover .
.PHONY: fuzz .PHONY: fuzz
fuzz: $(GOFUZZBUILD) $(GOFUZZ) fuzz:
@echo "==> Fuzz testing" @echo "==> Running Fuzz Tests"
$(GOFUZZBUILD) go test -fuzz=FuzzNewVersion -fuzztime=15s .
$(GOFUZZ) -workdir=_fuzz go test -fuzz=FuzzStrictNewVersion -fuzztime=15s .
go test -fuzz=FuzzNewConstraint -fuzztime=15s .
$(GOLANGCI_LINT): $(GOLANGCI_LINT):
# Install golangci-lint. The configuration for it is in the .golangci.yml # Install golangci-lint. The configuration for it is in the .golangci.yml
# file in the root of the repository # file in the root of the repository
echo ${GOPATH} echo ${GOPATH}
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1 curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1
$(GOFUZZBUILD):
cd / && go get -u github.com/dvyukov/go-fuzz/go-fuzz-build
$(GOFUZZ):
cd / && go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-dep

View file

@ -18,18 +18,20 @@ If you are looking for a command line tool for version comparisons please see
## Package Versions ## Package Versions
Note, import `github.com/github.com/Masterminds/semver/v3` to use the latest version.
There are three major versions fo the `semver` package. There are three major versions fo the `semver` package.
* 3.x.x is the new stable and active version. This version is focused on constraint * 3.x.x is the stable and active version. This version is focused on constraint
compatibility for range handling in other tools from other languages. It has compatibility for range handling in other tools from other languages. It has
a similar API to the v1 releases. The development of this version is on the master a similar API to the v1 releases. The development of this version is on the master
branch. The documentation for this version is below. branch. The documentation for this version is below.
* 2.x was developed primarily for [dep](https://github.com/golang/dep). There are * 2.x was developed primarily for [dep](https://github.com/golang/dep). There are
no tagged releases and the development was performed by [@sdboyer](https://github.com/sdboyer). no tagged releases and the development was performed by [@sdboyer](https://github.com/sdboyer).
There are API breaking changes from v1. This version lives on the [2.x branch](https://github.com/Masterminds/semver/tree/2.x). There are API breaking changes from v1. This version lives on the [2.x branch](https://github.com/Masterminds/semver/tree/2.x).
* 1.x.x is the most widely used version with numerous tagged releases. This is the * 1.x.x is the original release. It is no longer maintained. You should use the
previous stable and is still maintained for bug fixes. The development, to fix v3 release instead. You can read the documentation for the 1.x.x release
bugs, occurs on the release-1 branch. You can read the documentation [here](https://github.com/Masterminds/semver/blob/release-1/README.md). [here](https://github.com/Masterminds/semver/blob/release-1/README.md).
## Parsing Semantic Versions ## Parsing Semantic Versions
@ -242,3 +244,15 @@ for _, m := range msgs {
If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues) If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues)
or [create a pull request](https://github.com/Masterminds/semver/pulls). or [create a pull request](https://github.com/Masterminds/semver/pulls).
## Security
Security is an important consideration for this project. The project currently
uses the following tools to help discover security issues:
* [CodeQL](https://github.com/Masterminds/semver)
* [gosec](https://github.com/securego/gosec)
* Daily Fuzz testing
If you believe you have found a security vulnerability you can privately disclose
it through the [GitHub security page](https://github.com/Masterminds/semver/security).

19
vendor/github.com/Masterminds/semver/v3/SECURITY.md generated vendored Normal file
View file

@ -0,0 +1,19 @@
# Security Policy
## Supported Versions
The following versions of semver are currently supported:
| Version | Supported |
| ------- | ------------------ |
| 3.x | :white_check_mark: |
| 2.x | :x: |
| 1.x | :x: |
Fixes are only released for the latest minor version in the form of a patch release.
## Reporting a Vulnerability
You can privately disclose a vulnerability through GitHubs
[private vulnerability reporting](https://github.com/Masterminds/semver/security/advisories)
mechanism.

View file

@ -586,7 +586,7 @@ func rewriteRange(i string) string {
} }
o := i o := i
for _, v := range m { for _, v := range m {
t := fmt.Sprintf(">= %s, <= %s", v[1], v[11]) t := fmt.Sprintf(">= %s, <= %s ", v[1], v[11])
o = strings.Replace(o, v[0], t, 1) o = strings.Replace(o, v[0], t, 1)
} }

View file

@ -1,22 +0,0 @@
// +build gofuzz
package semver
func Fuzz(data []byte) int {
d := string(data)
// Test NewVersion
_, _ = NewVersion(d)
// Test StrictNewVersion
_, _ = StrictNewVersion(d)
// Test NewConstraint
_, _ = NewConstraint(d)
// The return value should be 0 normally, 1 if the priority in future tests
// should be increased, and -1 if future tests should skip passing in that
// data. We do not have a reason to change priority so 0 is always returned.
// There are example tests that do this.
return 0
}

View file

@ -1,6 +0,0 @@
language: go
go:
- 1.6
- 1.7
- 1.8

View file

@ -1,7 +1,7 @@
.PHONY: ci generate clean .PHONY: ci generate clean
ci: clean generate ci: clean generate
go test -v ./... go test -race -v ./...
generate: generate:
go generate . go generate .

View file

@ -7,8 +7,8 @@ http.Handlers.
Doing this requires non-trivial wrapping of the http.ResponseWriter interface, Doing this requires non-trivial wrapping of the http.ResponseWriter interface,
which is also exposed for users interested in a more low-level API. which is also exposed for users interested in a more low-level API.
[![GoDoc](https://godoc.org/github.com/felixge/httpsnoop?status.svg)](https://godoc.org/github.com/felixge/httpsnoop) [![Go Reference](https://pkg.go.dev/badge/github.com/felixge/httpsnoop.svg)](https://pkg.go.dev/github.com/felixge/httpsnoop)
[![Build Status](https://travis-ci.org/felixge/httpsnoop.svg?branch=master)](https://travis-ci.org/felixge/httpsnoop) [![Build Status](https://github.com/felixge/httpsnoop/actions/workflows/main.yaml/badge.svg)](https://github.com/felixge/httpsnoop/actions/workflows/main.yaml)
## Usage Example ## Usage Example

View file

@ -52,7 +52,7 @@ func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWri
return func(code int) { return func(code int) {
next(code) next(code)
if !headerWritten { if !(code >= 100 && code <= 199) && !headerWritten {
m.Code = code m.Code = code
headerWritten = true headerWritten = true
} }

View file

@ -1,5 +1,5 @@
// +build go1.8 // +build go1.8
// Code generated by "httpsnoop/codegen"; DO NOT EDIT // Code generated by "httpsnoop/codegen"; DO NOT EDIT.
package httpsnoop package httpsnoop

View file

@ -1,5 +1,5 @@
// +build !go1.8 // +build !go1.8
// Code generated by "httpsnoop/codegen"; DO NOT EDIT // Code generated by "httpsnoop/codegen"; DO NOT EDIT.
package httpsnoop package httpsnoop

View file

@ -4,53 +4,58 @@ linters-settings:
golint: golint:
min-confidence: 0 min-confidence: 0
gocyclo: gocyclo:
min-complexity: 40 min-complexity: 45
gocognit:
min-complexity: 40
maligned: maligned:
suggest-new: true suggest-new: true
dupl: dupl:
threshold: 150 threshold: 200
goconst: goconst:
min-len: 2 min-len: 2
min-occurrences: 4 min-occurrences: 3
linters: linters:
enable-all: true enable-all: true
disable: disable:
- maligned - maligned
- unparam
- lll - lll
- gochecknoglobals
- gochecknoinits - gochecknoinits
# scopelint is useful, but also reports false positives - gochecknoglobals
# that unfortunately can't be disabled. So we disable the - funlen
# linter rather than changing code that works.
# see: https://github.com/kyoh86/scopelint/issues/4
- scopelint
- godox - godox
- gocognit - gocognit
#- whitespace - whitespace
- wsl - wsl
- funlen
- testpackage
- wrapcheck - wrapcheck
#- nlreturn - testpackage
- nlreturn
- gomnd - gomnd
- goerr113
- exhaustivestruct - exhaustivestruct
#- errorlint - goerr113
#- nestif - errorlint
- gofumpt - nestif
- godot - godot
- gci - gofumpt
- dogsled
- paralleltest - paralleltest
- tparallel - tparallel
- thelper - thelper
- ifshort - ifshort
- forbidigo
- cyclop
- varnamelen
- exhaustruct - exhaustruct
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns - nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase - nosnakecase

View file

@ -1,8 +1,5 @@
# OpenAPI initiative analysis # OpenAPI analysis [![Build Status](https://github.com/go-openapi/analysis/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/analysis/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/analysis/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/analysis)
[![Build Status](https://travis-ci.org/go-openapi/analysis.svg?branch=master)](https://travis-ci.org/go-openapi/analysis)
[![Build status](https://ci.appveyor.com/api/projects/status/x377t5o9ennm847o/branch/master?svg=true)](https://ci.appveyor.com/project/casualjim/go-openapi/analysis/branch/master)
[![codecov](https://codecov.io/gh/go-openapi/analysis/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/analysis)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/analysis/master/LICENSE) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/analysis/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/analysis.svg)](https://pkg.go.dev/github.com/go-openapi/analysis) [![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/analysis.svg)](https://pkg.go.dev/github.com/go-openapi/analysis)
@ -13,12 +10,12 @@ A foundational library to analyze an OAI specification document for easier reaso
## What's inside? ## What's inside?
* A analyzer providing methods to walk the functional content of a specification * An analyzer providing methods to walk the functional content of a specification
* A spec flattener producing a self-contained document bundle, while preserving `$ref`s * A spec flattener producing a self-contained document bundle, while preserving `$ref`s
* A spec merger ("mixin") to merge several spec documents into a primary spec * A spec merger ("mixin") to merge several spec documents into a primary spec
* A spec "fixer" ensuring that response descriptions are non empty * A spec "fixer" ensuring that response descriptions are non empty
[Documentation](https://godoc.org/github.com/go-openapi/analysis) [Documentation](https://pkg.go.dev/github.com/go-openapi/analysis)
## FAQ ## FAQ
@ -28,4 +25,3 @@ A foundational library to analyze an OAI specification document for easier reaso
> This package currently only supports OpenAPI 2.0 (aka Swagger 2.0). > This package currently only supports OpenAPI 2.0 (aka Swagger 2.0).
> There is no plan to make it evolve toward supporting OpenAPI 3.x. > There is no plan to make it evolve toward supporting OpenAPI 3.x.
> This [discussion thread](https://github.com/go-openapi/spec/issues/21) relates the full story. > This [discussion thread](https://github.com/go-openapi/spec/issues/21) relates the full story.
>

View file

@ -1,32 +0,0 @@
version: "0.1.{build}"
clone_folder: C:\go-openapi\analysis
shallow_clone: true # for startup speed
pull_requests:
do_not_increment_build_number: true
#skip_tags: true
#skip_branch_with_pr: true
# appveyor.yml
build: off
environment:
GOPATH: c:\gopath
stack: go 1.16
test_script:
- go test -v -timeout 20m ./...
deploy: off
notifications:
- provider: Slack
incoming_webhook: https://hooks.slack.com/services/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
auth_token:
secure: Sf7kZf7ZGbnwWUMpffHwMu5A0cHkLK2MYY32LNTPj4+/3qC3Ghl7+9v4TSLOqOlCwdRNjOGblAq7s+GDJed6/xgRQl1JtCi1klzZNrYX4q01pgTPvvGcwbBkIYgeMaPeIRcK9OZnud7sRXdttozgTOpytps2U6Js32ip7uj5mHSg2ub0FwoSJwlS6dbezZ8+eDhoha0F/guY99BEwx8Bd+zROrT2TFGsSGOFGN6wFc7moCqTHO/YkWib13a2QNXqOxCCVBy/lt76Wp+JkeFppjHlzs/2lP3EAk13RIUAaesdEUHvIHrzCyNJEd3/+KO2DzsWOYfpktd+KBCvgaYOsoo7ubdT3IROeAegZdCgo/6xgCEsmFc9ZcqCfN5yNx2A+BZ2Vwmpws+bQ1E1+B5HDzzaiLcYfG4X2O210QVGVDLWsv1jqD+uPYeHY2WRfh5ZsIUFvaqgUEnwHwrK44/8REAhQavt1QAj5uJpsRd7CkRVPWRNK+yIky+wgbVUFEchRNmS55E7QWf+W4+4QZkQi7vUTMc9nbTUu2Es9NfvfudOpM2wZbn98fjpb/qq/nRv6Bk+ca+7XD5/IgNLMbWp2ouDdzbiHLCOfDUiHiDJhLfFZx9Bwo7ZwfzeOlbrQX66bx7xRKYmOe4DLrXhNcpbsMa8qbfxlZRCmYbubB/Y8h4=
channel: bots
on_build_success: false
on_build_failure: true
on_build_status_changed: true

View file

@ -16,27 +16,27 @@
Package analysis provides methods to work with a Swagger specification document from Package analysis provides methods to work with a Swagger specification document from
package go-openapi/spec. package go-openapi/spec.
Analyzing a specification ## Analyzing a specification
An analysed specification object (type Spec) provides methods to work with swagger definition. An analysed specification object (type Spec) provides methods to work with swagger definition.
Flattening or expanding a specification ## Flattening or expanding a specification
Flattening a specification bundles all remote $ref in the main spec document. Flattening a specification bundles all remote $ref in the main spec document.
Depending on flattening options, additional preprocessing may take place: Depending on flattening options, additional preprocessing may take place:
- full flattening: replacing all inline complex constructs by a named entry in #/definitions - full flattening: replacing all inline complex constructs by a named entry in #/definitions
- expand: replace all $ref's in the document by their expanded content - expand: replace all $ref's in the document by their expanded content
Merging several specifications ## Merging several specifications
Mixin several specifications merges all Swagger constructs, and warns about found conflicts. Mixin several specifications merges all Swagger constructs, and warns about found conflicts.
Fixing a specification ## Fixing a specification
Unmarshalling a specification with golang json unmarshalling may lead to Unmarshalling a specification with golang json unmarshalling may lead to
some unwanted result on present but empty fields. some unwanted result on present but empty fields.
Analyzing a Swagger schema ## Analyzing a Swagger schema
Swagger schemas are analyzed to determine their complexity and qualify their content. Swagger schemas are analyzed to determine their complexity and qualify their content.
*/ */

View file

@ -62,7 +62,6 @@ func newContext() *context {
// //
// There is a minimal and a full flattening mode. // There is a minimal and a full flattening mode.
// //
//
// Minimally flattening a spec means: // Minimally flattening a spec means:
// - Expanding parameters, responses, path items, parameter items and header items (references to schemas are left // - Expanding parameters, responses, path items, parameter items and header items (references to schemas are left
// unscathed) // unscathed)
@ -79,7 +78,6 @@ func newContext() *context {
// Otherwise, they are simply expanded. // Otherwise, they are simply expanded.
// Self-referencing JSON pointers cannot resolve to a type and trigger an error. // Self-referencing JSON pointers cannot resolve to a type and trigger an error.
// //
//
// Minimal flattening is necessary and sufficient for codegen rendering using go-swagger. // Minimal flattening is necessary and sufficient for codegen rendering using go-swagger.
// //
// Fully flattening a spec means: // Fully flattening a spec means:
@ -108,7 +106,6 @@ func newContext() *context {
// - merge allOf with validation only // - merge allOf with validation only
// - merge allOf with extensions only // - merge allOf with extensions only
// - ... // - ...
//
func Flatten(opts FlattenOpts) error { func Flatten(opts FlattenOpts) error {
debugLog("FlattenOpts: %#v", opts) debugLog("FlattenOpts: %#v", opts)
@ -270,6 +267,12 @@ func nameInlinedSchemas(opts *FlattenOpts) error {
} }
func removeUnused(opts *FlattenOpts) { func removeUnused(opts *FlattenOpts) {
for removeUnusedSinglePass(opts) {
// continue until no unused definition remains
}
}
func removeUnusedSinglePass(opts *FlattenOpts) (hasRemoved bool) {
expected := make(map[string]struct{}) expected := make(map[string]struct{})
for k := range opts.Swagger().Definitions { for k := range opts.Swagger().Definitions {
expected[path.Join(definitionsPath, jsonpointer.Escape(k))] = struct{}{} expected[path.Join(definitionsPath, jsonpointer.Escape(k))] = struct{}{}
@ -280,6 +283,7 @@ func removeUnused(opts *FlattenOpts) {
} }
for k := range expected { for k := range expected {
hasRemoved = true
debugLog("removing unused definition %s", path.Base(k)) debugLog("removing unused definition %s", path.Base(k))
if opts.Verbose { if opts.Verbose {
log.Printf("info: removing unused definition: %s", path.Base(k)) log.Printf("info: removing unused definition: %s", path.Base(k))
@ -288,6 +292,8 @@ func removeUnused(opts *FlattenOpts) {
} }
opts.Spec.reload() // re-analyze opts.Spec.reload() // re-analyze
return hasRemoved
} }
func importKnownRef(entry sortref.RefRevIdx, refStr, newName string, opts *FlattenOpts) error { func importKnownRef(entry sortref.RefRevIdx, refStr, newName string, opts *FlattenOpts) error {
@ -334,7 +340,7 @@ func importNewRef(entry sortref.RefRevIdx, refStr string, opts *FlattenOpts) err
} }
// generate a unique name - isOAIGen means that a naming conflict was resolved by changing the name // generate a unique name - isOAIGen means that a naming conflict was resolved by changing the name
newName, isOAIGen = uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref)) newName, isOAIGen = uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref, opts))
debugLog("new name for [%s]: %s - with name conflict:%t", strings.Join(entry.Keys, ", "), newName, isOAIGen) debugLog("new name for [%s]: %s - with name conflict:%t", strings.Join(entry.Keys, ", "), newName, isOAIGen)
opts.flattenContext.resolved[refStr] = newName opts.flattenContext.resolved[refStr] = newName
@ -652,6 +658,7 @@ func namePointers(opts *FlattenOpts) error {
refsToReplace := make(map[string]SchemaRef, len(opts.Spec.references.schemas)) refsToReplace := make(map[string]SchemaRef, len(opts.Spec.references.schemas))
for k, ref := range opts.Spec.references.allRefs { for k, ref := range opts.Spec.references.allRefs {
debugLog("name pointers: %q => %#v", k, ref)
if path.Dir(ref.String()) == definitionsPath { if path.Dir(ref.String()) == definitionsPath {
// this a ref to a top-level definition: ok // this a ref to a top-level definition: ok
continue continue
@ -769,6 +776,10 @@ func flattenAnonPointer(key string, v SchemaRef, refsToReplace map[string]Schema
// identifying edge case when the namer did nothing because we point to a non-schema object // identifying edge case when the namer did nothing because we point to a non-schema object
// no definition is created and we expand the $ref for all callers // no definition is created and we expand the $ref for all callers
debugLog("decide what to do with the schema pointed to: asch.IsSimpleSchema=%t, len(callers)=%d, parts.IsSharedParam=%t, parts.IsSharedResponse=%t",
asch.IsSimpleSchema, len(callers), parts.IsSharedParam(), parts.IsSharedResponse(),
)
if (!asch.IsSimpleSchema || len(callers) > 1) && !parts.IsSharedParam() && !parts.IsSharedResponse() { if (!asch.IsSimpleSchema || len(callers) > 1) && !parts.IsSharedParam() && !parts.IsSharedResponse() {
debugLog("replace JSON pointer at [%s] by definition: %s", key, v.Ref.String()) debugLog("replace JSON pointer at [%s] by definition: %s", key, v.Ref.String())
if err := namer.Name(v.Ref.String(), v.Schema, asch); err != nil { if err := namer.Name(v.Ref.String(), v.Schema, asch); err != nil {
@ -791,6 +802,7 @@ func flattenAnonPointer(key string, v SchemaRef, refsToReplace map[string]Schema
return nil return nil
} }
// everything that is a simple schema and not factorizable is expanded
debugLog("expand JSON pointer for key=%s", key) debugLog("expand JSON pointer for key=%s", key)
if err := replace.UpdateRefWithSchema(opts.Swagger(), key, v.Schema); err != nil { if err := replace.UpdateRefWithSchema(opts.Swagger(), key, v.Schema); err != nil {

View file

@ -33,12 +33,14 @@ func (isn *InlineSchemaNamer) Name(key string, schema *spec.Schema, aschema *Ana
} }
// create unique name // create unique name
newName, isOAIGen := uniqifyName(isn.Spec.Definitions, swag.ToJSONName(name)) mangle := mangler(isn.opts)
newName, isOAIGen := uniqifyName(isn.Spec.Definitions, mangle(name))
// clone schema // clone schema
sch := schutils.Clone(schema) sch := schutils.Clone(schema)
// replace values on schema // replace values on schema
debugLog("rewriting schema to ref: key=%s with new name: %s", key, newName)
if err := replace.RewriteSchemaToRef(isn.Spec, key, if err := replace.RewriteSchemaToRef(isn.Spec, key,
spec.MustCreateRef(path.Join(definitionsPath, newName))); err != nil { spec.MustCreateRef(path.Join(definitionsPath, newName))); err != nil {
return fmt.Errorf("error while creating definition %q from inline schema: %w", newName, err) return fmt.Errorf("error while creating definition %q from inline schema: %w", newName, err)
@ -149,13 +151,15 @@ func namesFromKey(parts sortref.SplitKey, aschema *AnalyzedSchema, operations ma
startIndex int startIndex int
) )
if parts.IsOperation() { switch {
case parts.IsOperation():
baseNames, startIndex = namesForOperation(parts, operations) baseNames, startIndex = namesForOperation(parts, operations)
} case parts.IsDefinition():
// definitions
if parts.IsDefinition() {
baseNames, startIndex = namesForDefinition(parts) baseNames, startIndex = namesForDefinition(parts)
default:
// this a non-standard pointer: build a name by concatenating its parts
baseNames = [][]string{parts}
startIndex = len(baseNames) + 1
} }
result := make([]string, 0, len(baseNames)) result := make([]string, 0, len(baseNames))
@ -169,6 +173,7 @@ func namesFromKey(parts sortref.SplitKey, aschema *AnalyzedSchema, operations ma
} }
sort.Strings(result) sort.Strings(result)
debugLog("names from parts: %v => %v", parts, result)
return result return result
} }
@ -256,10 +261,20 @@ func partAdder(aschema *AnalyzedSchema) sortref.PartAdder {
} }
} }
func nameFromRef(ref spec.Ref) string { func mangler(o *FlattenOpts) func(string) string {
if o.KeepNames {
return func(in string) string { return in }
}
return swag.ToJSONName
}
func nameFromRef(ref spec.Ref, o *FlattenOpts) string {
mangle := mangler(o)
u := ref.GetURL() u := ref.GetURL()
if u.Fragment != "" { if u.Fragment != "" {
return swag.ToJSONName(path.Base(u.Fragment)) return mangle(path.Base(u.Fragment))
} }
if u.Path != "" { if u.Path != "" {
@ -267,19 +282,19 @@ func nameFromRef(ref spec.Ref) string {
if bn != "" && bn != "/" { if bn != "" && bn != "/" {
ext := path.Ext(bn) ext := path.Ext(bn)
if ext != "" { if ext != "" {
return swag.ToJSONName(bn[:len(bn)-len(ext)]) return mangle(bn[:len(bn)-len(ext)])
} }
return swag.ToJSONName(bn) return mangle(bn)
} }
} }
return swag.ToJSONName(strings.ReplaceAll(u.Host, ".", " ")) return mangle(strings.ReplaceAll(u.Host, ".", " "))
} }
// GenLocation indicates from which section of the specification (models or operations) a definition has been created. // GenLocation indicates from which section of the specification (models or operations) a definition has been created.
// //
// This is reflected in the output spec with a "x-go-gen-location" extension. At the moment, this is is provided // This is reflected in the output spec with a "x-go-gen-location" extension. At the moment, this is provided
// for information only. // for information only.
func GenLocation(parts sortref.SplitKey) string { func GenLocation(parts sortref.SplitKey) string {
switch { switch {

View file

@ -26,6 +26,7 @@ type FlattenOpts struct {
Verbose bool // enable some reporting on possible name conflicts detected Verbose bool // enable some reporting on possible name conflicts detected
RemoveUnused bool // When true, remove unused parameters, responses and definitions after expansion/flattening RemoveUnused bool // When true, remove unused parameters, responses and definitions after expansion/flattening
ContinueOnError bool // Continue when spec expansion issues are found ContinueOnError bool // Continue when spec expansion issues are found
KeepNames bool // Do not attempt to jsonify names from references when flattening
/* Extra keys */ /* Extra keys */
_ struct{} // require keys _ struct{} // require keys

View file

@ -29,7 +29,7 @@
// GetLogger provides a prefix debug logger // GetLogger provides a prefix debug logger
func GetLogger(prefix string, debug bool) func(string, ...interface{}) { func GetLogger(prefix string, debug bool) func(string, ...interface{}) {
if debug { if debug {
logger := log.New(output, fmt.Sprintf("%s:", prefix), log.LstdFlags) logger := log.New(output, prefix+":", log.LstdFlags)
return func(msg string, args ...interface{}) { return func(msg string, args ...interface{}) {
_, file1, pos1, _ := runtime.Caller(1) _, file1, pos1, _ := runtime.Caller(1)
@ -37,5 +37,5 @@ func GetLogger(prefix string, debug bool) func(string, ...interface{}) {
} }
} }
return func(msg string, args ...interface{}) {} return func(_ string, _ ...interface{}) {}
} }

View file

@ -1,6 +1,7 @@
package replace package replace
import ( import (
"encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"os" "os"
@ -40,6 +41,8 @@ func RewriteSchemaToRef(sp *spec.Swagger, key string, ref spec.Ref) error {
if refable.Schema != nil { if refable.Schema != nil {
refable.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} refable.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
} }
case map[string]interface{}: // this happens e.g. if a schema points to an extension unmarshaled as map[string]interface{}
return rewriteParentRef(sp, key, ref)
default: default:
return fmt.Errorf("no schema with ref found at %s for %T", key, value) return fmt.Errorf("no schema with ref found at %s for %T", key, value)
} }
@ -120,6 +123,9 @@ func rewriteParentRef(sp *spec.Swagger, key string, ref spec.Ref) error {
case spec.SchemaProperties: case spec.SchemaProperties:
container[entry] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}} container[entry] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
case *interface{}:
*container = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
// NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema // NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema
default: default:
@ -385,8 +391,9 @@ func DeepestRef(sp *spec.Swagger, opts *spec.ExpandOptions, ref spec.Ref) (*Deep
err := asSchema.UnmarshalJSON(asJSON) err := asSchema.UnmarshalJSON(asJSON)
if err != nil { if err != nil {
return nil, return nil,
fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T", fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T (%v)",
currentRef.String(), value) currentRef.String(), value, err,
)
} }
warnings = append(warnings, fmt.Sprintf("found $ref %q (response) interpreted as schema", currentRef.String())) warnings = append(warnings, fmt.Sprintf("found $ref %q (response) interpreted as schema", currentRef.String()))
@ -402,8 +409,9 @@ func DeepestRef(sp *spec.Swagger, opts *spec.ExpandOptions, ref spec.Ref) (*Deep
var asSchema spec.Schema var asSchema spec.Schema
if err := asSchema.UnmarshalJSON(asJSON); err != nil { if err := asSchema.UnmarshalJSON(asJSON); err != nil {
return nil, return nil,
fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T", fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T (%v)",
currentRef.String(), value) currentRef.String(), value, err,
)
} }
warnings = append(warnings, fmt.Sprintf("found $ref %q (parameter) interpreted as schema", currentRef.String())) warnings = append(warnings, fmt.Sprintf("found $ref %q (parameter) interpreted as schema", currentRef.String()))
@ -414,9 +422,25 @@ func DeepestRef(sp *spec.Swagger, opts *spec.ExpandOptions, ref spec.Ref) (*Deep
currentRef = asSchema.Ref currentRef = asSchema.Ref
default: default:
// fallback: attempts to resolve the pointer as a schema
if refable == nil {
break DOWNREF
}
asJSON, _ := json.Marshal(refable)
var asSchema spec.Schema
if err := asSchema.UnmarshalJSON(asJSON); err != nil {
return nil, return nil,
fmt.Errorf("unhandled type to resolve JSON pointer %s. Expected a Schema, got: %T", fmt.Errorf("unhandled type to resolve JSON pointer %s. Expected a Schema, got: %T (%v)",
currentRef.String(), value) currentRef.String(), value, err,
)
}
warnings = append(warnings, fmt.Sprintf("found $ref %q (%T) interpreted as schema", currentRef.String(), refable))
if asSchema.Ref.String() == "" {
break DOWNREF
}
currentRef = asSchema.Ref
} }
} }

View file

@ -69,7 +69,7 @@ func KeyParts(key string) SplitKey {
return res return res
} }
// SplitKey holds of the parts of a /-separated key, soi that their location may be determined. // SplitKey holds of the parts of a /-separated key, so that their location may be determined.
type SplitKey []string type SplitKey []string
// IsDefinition is true when the split key is in the #/definitions section of a spec // IsDefinition is true when the split key is in the #/definitions section of a spec

View file

@ -53,7 +53,7 @@
// collisions. // collisions.
func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string { func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string {
skipped := make([]string, 0, len(mixins)) skipped := make([]string, 0, len(mixins))
opIds := getOpIds(primary) opIDs := getOpIDs(primary)
initPrimary(primary) initPrimary(primary)
for i, m := range mixins { for i, m := range mixins {
@ -74,7 +74,7 @@ func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string {
skipped = append(skipped, mergeDefinitions(primary, m)...) skipped = append(skipped, mergeDefinitions(primary, m)...)
// merging paths requires a map of operationIDs to work with // merging paths requires a map of operationIDs to work with
skipped = append(skipped, mergePaths(primary, m, opIds, i)...) skipped = append(skipped, mergePaths(primary, m, opIDs, i)...)
skipped = append(skipped, mergeParameters(primary, m)...) skipped = append(skipped, mergeParameters(primary, m)...)
@ -84,9 +84,9 @@ func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string {
return skipped return skipped
} }
// getOpIds extracts all the paths.<path>.operationIds from the given // getOpIDs extracts all the paths.<path>.operationIds from the given
// spec and returns them as the keys in a map with 'true' values. // spec and returns them as the keys in a map with 'true' values.
func getOpIds(s *spec.Swagger) map[string]bool { func getOpIDs(s *spec.Swagger) map[string]bool {
rv := make(map[string]bool) rv := make(map[string]bool)
if s.Paths == nil { if s.Paths == nil {
return rv return rv
@ -179,7 +179,7 @@ func mergeDefinitions(primary *spec.Swagger, m *spec.Swagger) (skipped []string)
return return
} }
func mergePaths(primary *spec.Swagger, m *spec.Swagger, opIds map[string]bool, mixIndex int) (skipped []string) { func mergePaths(primary *spec.Swagger, m *spec.Swagger, opIDs map[string]bool, mixIndex int) (skipped []string) {
if m.Paths != nil { if m.Paths != nil {
for k, v := range m.Paths.Paths { for k, v := range m.Paths.Paths {
if _, exists := primary.Paths.Paths[k]; exists { if _, exists := primary.Paths.Paths[k]; exists {
@ -198,10 +198,10 @@ func mergePaths(primary *spec.Swagger, m *spec.Swagger, opIds map[string]bool, m
// all the proivded specs are already unique. // all the proivded specs are already unique.
piops := pathItemOps(v) piops := pathItemOps(v)
for _, piop := range piops { for _, piop := range piops {
if opIds[piop.ID] { if opIDs[piop.ID] {
piop.ID = fmt.Sprintf("%v%v%v", piop.ID, "Mixin", mixIndex) piop.ID = fmt.Sprintf("%v%v%v", piop.ID, "Mixin", mixIndex)
} }
opIds[piop.ID] = true opIDs[piop.ID] = true
} }
primary.Paths.Paths[k] = v primary.Paths.Paths[k] = v
} }
@ -367,7 +367,7 @@ func mergeSwaggerProps(primary *spec.Swagger, m *spec.Swagger) []string {
return skipped return skipped
} }
// nolint: unparam //nolint:unparam
func mergeExternalDocs(primary *spec.ExternalDocumentation, m *spec.ExternalDocumentation) []string { func mergeExternalDocs(primary *spec.ExternalDocumentation, m *spec.ExternalDocumentation) []string {
if primary.Description == "" { if primary.Description == "" {
primary.Description = m.Description primary.Description = m.Description

View file

@ -1,7 +1,7 @@
package analysis package analysis
import ( import (
"fmt" "errors"
"github.com/go-openapi/spec" "github.com/go-openapi/spec"
"github.com/go-openapi/strfmt" "github.com/go-openapi/strfmt"
@ -19,7 +19,7 @@ type SchemaOpts struct {
// patterns. // patterns.
func Schema(opts SchemaOpts) (*AnalyzedSchema, error) { func Schema(opts SchemaOpts) (*AnalyzedSchema, error) {
if opts.Schema == nil { if opts.Schema == nil {
return nil, fmt.Errorf("no schema to analyze") return nil, errors.New("no schema to analyze")
} }
a := &AnalyzedSchema{ a := &AnalyzedSchema{

View file

@ -4,45 +4,59 @@ linters-settings:
golint: golint:
min-confidence: 0 min-confidence: 0
gocyclo: gocyclo:
min-complexity: 30 min-complexity: 45
maligned: maligned:
suggest-new: true suggest-new: true
dupl: dupl:
threshold: 100 threshold: 200
goconst: goconst:
min-len: 2 min-len: 2
min-occurrences: 4 min-occurrences: 3
linters: linters:
enable-all: true enable-all: true
disable: disable:
- errname # this repo doesn't follow the convention advised by this linter
- maligned - maligned
- unparam
- lll - lll
- gochecknoinits
- gochecknoglobals - gochecknoglobals
- funlen
- godox - godox
- gocognit - gocognit
- whitespace - whitespace
- wsl - wsl
- funlen
- gochecknoglobals
- gochecknoinits
- scopelint
- wrapcheck - wrapcheck
- exhaustivestruct
- exhaustive
- nlreturn
- testpackage - testpackage
- gci - nlreturn
- gofumpt
- goerr113
- gomnd - gomnd
- tparallel - exhaustivestruct
- goerr113
- errorlint
- nestif - nestif
- godot - godot
- errorlint - gofumpt
- paralleltest - paralleltest
- tparallel - tparallel
- cyclop - thelper
- errname - ifshort
- varnamelen
- exhaustruct - exhaustruct
- maintidx - varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase

View file

@ -1,11 +1,8 @@
# OpenAPI errors # OpenAPI errors [![Build Status](https://github.com/go-openapi/errors/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/errors/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/errors/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/errors)
[![Build Status](https://travis-ci.org/go-openapi/errors.svg?branch=master)](https://travis-ci.org/go-openapi/errors)
[![codecov](https://codecov.io/gh/go-openapi/errors/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/errors)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/errors/master/LICENSE) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/errors/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/errors.svg)](https://pkg.go.dev/github.com/go-openapi/errors) [![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/errors.svg)](https://pkg.go.dev/github.com/go-openapi/errors)
[![GolangCI](https://golangci.com/badges/github.com/go-openapi/errors.svg)](https://golangci.com)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/errors)](https://goreportcard.com/report/github.com/go-openapi/errors) [![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/errors)](https://goreportcard.com/report/github.com/go-openapi/errors)
Shared errors and error interface used throughout the various libraries found in the go-openapi toolkit. Shared errors and error interface used throughout the various libraries found in the go-openapi toolkit.

View file

@ -55,9 +55,15 @@ func (a apiError) MarshalJSON() ([]byte, error) {
// New creates a new API error with a code and a message // New creates a new API error with a code and a message
func New(code int32, message string, args ...interface{}) Error { func New(code int32, message string, args ...interface{}) Error {
if len(args) > 0 { if len(args) > 0 {
return &apiError{code, fmt.Sprintf(message, args...)} return &apiError{
code: code,
message: fmt.Sprintf(message, args...),
}
}
return &apiError{
code: code,
message: message,
} }
return &apiError{code, message}
} }
// NotFound creates a new not found error // NotFound creates a new not found error
@ -130,10 +136,14 @@ func flattenComposite(errs *CompositeError) *CompositeError {
// MethodNotAllowed creates a new method not allowed error // MethodNotAllowed creates a new method not allowed error
func MethodNotAllowed(requested string, allow []string) Error { func MethodNotAllowed(requested string, allow []string) Error {
msg := fmt.Sprintf("method %s is not allowed, but [%s] are", requested, strings.Join(allow, ",")) msg := fmt.Sprintf("method %s is not allowed, but [%s] are", requested, strings.Join(allow, ","))
return &MethodNotAllowedError{code: http.StatusMethodNotAllowed, Allowed: allow, message: msg} return &MethodNotAllowedError{
code: http.StatusMethodNotAllowed,
Allowed: allow,
message: msg,
}
} }
// ServeError the error handler interface implementation // ServeError implements the http error handler interface
func ServeError(rw http.ResponseWriter, r *http.Request, err error) { func ServeError(rw http.ResponseWriter, r *http.Request, err error) {
rw.Header().Set("Content-Type", "application/json") rw.Header().Set("Content-Type", "application/json")
switch e := err.(type) { switch e := err.(type) {

View file

@ -120,6 +120,10 @@ func (c *CompositeError) Error() string {
return c.message return c.message
} }
func (c *CompositeError) Unwrap() []error {
return c.Errors
}
// MarshalJSON implements the JSON encoding interface // MarshalJSON implements the JSON encoding interface
func (c CompositeError) MarshalJSON() ([]byte, error) { func (c CompositeError) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]interface{}{ return json.Marshal(map[string]interface{}{
@ -133,7 +137,7 @@ func (c CompositeError) MarshalJSON() ([]byte, error) {
func CompositeValidationError(errors ...error) *CompositeError { func CompositeValidationError(errors ...error) *CompositeError {
return &CompositeError{ return &CompositeError{
code: CompositeErrorCode, code: CompositeErrorCode,
Errors: append([]error{}, errors...), Errors: append(make([]error, 0, len(errors)), errors...),
message: "validation failure list", message: "validation failure list",
} }
} }

5
vendor/github.com/go-openapi/inflect/.gitignore generated vendored Normal file
View file

@ -0,0 +1,5 @@
secrets.yml
coverage.out
coverage.txt
*.cov
.idea

61
vendor/github.com/go-openapi/inflect/.golangci.yml generated vendored Normal file
View file

@ -0,0 +1,61 @@
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0
gocyclo:
min-complexity: 45
maligned:
suggest-new: true
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
linters:
enable-all: true
disable:
- maligned
- unparam
- lll
- gochecknoinits
- gochecknoglobals
- funlen
- godox
- gocognit
- whitespace
- wsl
- wrapcheck
- testpackage
- nlreturn
- gomnd
- exhaustivestruct
- goerr113
- errorlint
- nestif
- godot
- gofumpt
- paralleltest
- tparallel
- thelper
- ifshort
- exhaustruct
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase

View file

@ -1 +0,0 @@
swp$

View file

@ -1,168 +0,0 @@
INSTALLATION
go get bitbucket.org/pkg/inflect
PACKAGE
package inflect
FUNCTIONS
func AddAcronym(word string)
func AddHuman(suffix, replacement string)
func AddIrregular(singular, plural string)
func AddPlural(suffix, replacement string)
func AddSingular(suffix, replacement string)
func AddUncountable(word string)
func Asciify(word string) string
func Camelize(word string) string
func CamelizeDownFirst(word string) string
func Capitalize(word string) string
func Dasherize(word string) string
func ForeignKey(word string) string
func ForeignKeyCondensed(word string) string
func Humanize(word string) string
func Ordinalize(word string) string
func Parameterize(word string) string
func ParameterizeJoin(word, sep string) string
func Pluralize(word string) string
func Singularize(word string) string
func Tableize(word string) string
func Titleize(word string) string
func Typeify(word string) string
func Uncountables() map[string]bool
func Underscore(word string) string
TYPES
type Rule struct {
// contains filtered or unexported fields
}
used by rulesets
type Ruleset struct {
// contains filtered or unexported fields
}
a Ruleset is the config of pluralization rules
you can extend the rules with the Add* methods
func NewDefaultRuleset() *Ruleset
create a new ruleset and load it with the default
set of common English pluralization rules
func NewRuleset() *Ruleset
create a blank ruleset. Unless you are going to
build your own rules from scratch you probably
won't need this and can just use the defaultRuleset
via the global inflect.* methods
func (rs *Ruleset) AddAcronym(word string)
if you use acronym you may need to add them to the ruleset
to prevent Underscored words of things like "HTML" coming out
as "h_t_m_l"
func (rs *Ruleset) AddHuman(suffix, replacement string)
Human rules are applied by humanize to show more friendly
versions of words
func (rs *Ruleset) AddIrregular(singular, plural string)
Add any inconsistant pluralizing/sinularizing rules
to the set here.
func (rs *Ruleset) AddPlural(suffix, replacement string)
add a pluralization rule
func (rs *Ruleset) AddPluralExact(suffix, replacement string, exact bool)
add a pluralization rule with full string match
func (rs *Ruleset) AddSingular(suffix, replacement string)
add a singular rule
func (rs *Ruleset) AddSingularExact(suffix, replacement string, exact bool)
same as AddSingular but you can set `exact` to force
a full string match
func (rs *Ruleset) AddUncountable(word string)
add a word to this ruleset that has the same singular and plural form
for example: "rice"
func (rs *Ruleset) Asciify(word string) string
transforms latin characters like é -> e
func (rs *Ruleset) Camelize(word string) string
"dino_party" -> "DinoParty"
func (rs *Ruleset) CamelizeDownFirst(word string) string
same as Camelcase but with first letter downcased
func (rs *Ruleset) Capitalize(word string) string
uppercase first character
func (rs *Ruleset) Dasherize(word string) string
"SomeText" -> "some-text"
func (rs *Ruleset) ForeignKey(word string) string
an underscored foreign key name "Person" -> "person_id"
func (rs *Ruleset) ForeignKeyCondensed(word string) string
a foreign key (with an underscore) "Person" -> "personid"
func (rs *Ruleset) Humanize(word string) string
First letter of sentance captitilized
Uses custom friendly replacements via AddHuman()
func (rs *Ruleset) Ordinalize(str string) string
"1031" -> "1031st"
func (rs *Ruleset) Parameterize(word string) string
param safe dasherized names like "my-param"
func (rs *Ruleset) ParameterizeJoin(word, sep string) string
param safe dasherized names with custom seperator
func (rs *Ruleset) Pluralize(word string) string
returns the plural form of a singular word
func (rs *Ruleset) Singularize(word string) string
returns the singular form of a plural word
func (rs *Ruleset) Tableize(word string) string
Rails style pluralized table names: "SuperPerson" -> "super_people"
func (rs *Ruleset) Titleize(word string) string
Captitilize every word in sentance "hello there" -> "Hello There"
func (rs *Ruleset) Typeify(word string) string
"something_like_this" -> "SomethingLikeThis"
func (rs *Ruleset) Uncountables() map[string]bool
func (rs *Ruleset) Underscore(word string) string
lowercase underscore version "BigBen" -> "big_ben"

18
vendor/github.com/go-openapi/inflect/README.md generated vendored Normal file
View file

@ -0,0 +1,18 @@
# inflect [![Build Status](https://github.com/go-openapi/inflect/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/inflect/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/inflect/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/inflect)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/inflect/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/inflect.svg)](https://pkg.go.dev/github.com/go-openapi/inflect)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/inflect)](https://goreportcard.com/report/github.com/go-openapi/inflect)
A package to pluralize words.
Originally forked from fork of https://bitbucket.org/pkg/inflect under a MIT License.
A golang library applying grammar rules to English words.
> This package provides a basic set of functions applying
> grammar rules to inflect English words, modify case style
> (Capitalize, camelCase, snake_case, etc.).
>
> Acronyms are properly handled. A common use case is word pluralization.

View file

@ -24,7 +24,6 @@ type Ruleset struct {
singulars []*Rule singulars []*Rule
humans []*Rule humans []*Rule
acronyms []*Rule acronyms []*Rule
acronymMatcher *regexp.Regexp
} }
// create a blank ruleset. Unless you are going to // create a blank ruleset. Unless you are going to
@ -282,7 +281,7 @@ func (rs *Ruleset) AddHuman(suffix, replacement string) {
rs.humans = append([]*Rule{r}, rs.humans...) rs.humans = append([]*Rule{r}, rs.humans...)
} }
// Add any inconsistant pluralizing/sinularizing rules // Add any inconsistent pluralizing/sinularizing rules
// to the set here. // to the set here.
func (rs *Ruleset) AddIrregular(singular, plural string) { func (rs *Ruleset) AddIrregular(singular, plural string) {
delete(rs.uncountables, singular) delete(rs.uncountables, singular)
@ -387,7 +386,7 @@ func (rs *Ruleset) Titleize(word string) string {
func (rs *Ruleset) safeCaseAcronyms(word string) string { func (rs *Ruleset) safeCaseAcronyms(word string) string {
// convert an acroymn like HTML into Html // convert an acroymn like HTML into Html
for _, rule := range rs.acronyms { for _, rule := range rs.acronyms {
word = strings.Replace(word, rule.suffix, rule.replacement, -1) word = strings.ReplaceAll(word, rule.suffix, rule.replacement)
} }
return word return word
} }
@ -409,7 +408,7 @@ func (rs *Ruleset) Humanize(word string) string {
word = replaceLast(word, "_id", "") // strip foreign key kinds word = replaceLast(word, "_id", "") // strip foreign key kinds
// replace and strings in humans list // replace and strings in humans list
for _, rule := range rs.humans { for _, rule := range rs.humans {
word = strings.Replace(word, rule.suffix, rule.replacement, -1) word = strings.ReplaceAll(word, rule.suffix, rule.replacement)
} }
sentance := rs.seperatedWords(word, " ") sentance := rs.seperatedWords(word, " ")
return strings.ToUpper(sentance[:1]) + sentance[1:] return strings.ToUpper(sentance[:1]) + sentance[1:]
@ -430,19 +429,19 @@ func (rs *Ruleset) Tableize(word string) string {
return rs.Pluralize(rs.Underscore(rs.Typeify(word))) return rs.Pluralize(rs.Underscore(rs.Typeify(word)))
} }
var notUrlSafe *regexp.Regexp = regexp.MustCompile(`[^\w\d\-_ ]`) var notURLSafe = regexp.MustCompile(`[^\w\d\-_ ]`)
// param safe dasherized names like "my-param" // param safe dasherized names like "my-param"
func (rs *Ruleset) Parameterize(word string) string { func (rs *Ruleset) Parameterize(word string) string {
return ParameterizeJoin(word, "-") return ParameterizeJoin(word, "-")
} }
// param safe dasherized names with custom seperator // param safe dasherized names with custom separator
func (rs *Ruleset) ParameterizeJoin(word, sep string) string { func (rs *Ruleset) ParameterizeJoin(word, sep string) string {
word = strings.ToLower(word) word = strings.ToLower(word)
word = rs.Asciify(word) word = rs.Asciify(word)
word = notUrlSafe.ReplaceAllString(word, "") word = notURLSafe.ReplaceAllString(word, "")
word = strings.Replace(word, " ", sep, -1) word = strings.ReplaceAll(word, " ", sep)
if len(sep) > 0 { if len(sep) > 0 {
squash, err := regexp.Compile(sep + "+") squash, err := regexp.Compile(sep + "+")
if err == nil { if err == nil {
@ -453,7 +452,7 @@ func (rs *Ruleset) ParameterizeJoin(word, sep string) string {
return word return word
} }
var lookalikes map[string]*regexp.Regexp = map[string]*regexp.Regexp{ var lookalikes = map[string]*regexp.Regexp{
"A": regexp.MustCompile(`À|Á|Â|Ã|Ä|Å`), "A": regexp.MustCompile(`À|Á|Â|Ã|Ä|Å`),
"AE": regexp.MustCompile(`Æ`), "AE": regexp.MustCompile(`Æ`),
"C": regexp.MustCompile(`Ç`), "C": regexp.MustCompile(`Ç`),
@ -487,7 +486,7 @@ func (rs *Ruleset) Asciify(word string) string {
return word return word
} }
var tablePrefix *regexp.Regexp = regexp.MustCompile(`^[^.]*\.`) var tablePrefix = regexp.MustCompile(`^[^.]*\.`)
// "something_like_this" -> "SomethingLikeThis" // "something_like_this" -> "SomethingLikeThis"
func (rs *Ruleset) Typeify(word string) string { func (rs *Ruleset) Typeify(word string) string {
@ -642,13 +641,13 @@ func reverse(s string) string {
func isSpacerChar(c rune) bool { func isSpacerChar(c rune) bool {
switch { switch {
case c == rune("_"[0]): case c == '_':
return true return true
case c == rune(" "[0]): case c == ':':
return true return true
case c == rune(":"[0]): case c == '-':
return true return true
case c == rune("-"[0]): case unicode.IsSpace(c):
return true return true
} }
return false return false

61
vendor/github.com/go-openapi/jsonpointer/.golangci.yml generated vendored Normal file
View file

@ -0,0 +1,61 @@
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0
gocyclo:
min-complexity: 45
maligned:
suggest-new: true
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
linters:
enable-all: true
disable:
- maligned
- unparam
- lll
- gochecknoinits
- gochecknoglobals
- funlen
- godox
- gocognit
- whitespace
- wsl
- wrapcheck
- testpackage
- nlreturn
- gomnd
- exhaustivestruct
- goerr113
- errorlint
- nestif
- godot
- gofumpt
- paralleltest
- tparallel
- thelper
- ifshort
- exhaustruct
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase

View file

@ -1,6 +1,10 @@
# gojsonpointer [![Build Status](https://travis-ci.org/go-openapi/jsonpointer.svg?branch=master)](https://travis-ci.org/go-openapi/jsonpointer) [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) # gojsonpointer [![Build Status](https://github.com/go-openapi/jsonpointer/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/jsonpointer/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/jsonpointer.svg)](https://pkg.go.dev/github.com/go-openapi/jsonpointer)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/jsonpointer)](https://goreportcard.com/report/github.com/go-openapi/jsonpointer)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer)
An implementation of JSON Pointer - Go language An implementation of JSON Pointer - Go language
## Status ## Status

View file

@ -26,6 +26,7 @@
package jsonpointer package jsonpointer
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
@ -40,6 +41,7 @@
pointerSeparator = `/` pointerSeparator = `/`
invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator
notFound = `Can't find the pointer in the document`
) )
var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem() var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
@ -48,13 +50,13 @@
// JSONPointable is an interface for structs to implement when they need to customize the // JSONPointable is an interface for structs to implement when they need to customize the
// json pointer process // json pointer process
type JSONPointable interface { type JSONPointable interface {
JSONLookup(string) (interface{}, error) JSONLookup(string) (any, error)
} }
// JSONSetable is an interface for structs to implement when they need to customize the // JSONSetable is an interface for structs to implement when they need to customize the
// json pointer process // json pointer process
type JSONSetable interface { type JSONSetable interface {
JSONSet(string, interface{}) error JSONSet(string, any) error
} }
// New creates a new json pointer for the given string // New creates a new json pointer for the given string
@ -81,9 +83,7 @@ func (p *Pointer) parse(jsonPointerString string) error {
err = errors.New(invalidStart) err = errors.New(invalidStart)
} else { } else {
referenceTokens := strings.Split(jsonPointerString, pointerSeparator) referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
for _, referenceToken := range referenceTokens[1:] { p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...)
p.referenceTokens = append(p.referenceTokens, referenceToken)
}
} }
} }
@ -91,38 +91,58 @@ func (p *Pointer) parse(jsonPointerString string) error {
} }
// Get uses the pointer to retrieve a value from a JSON document // Get uses the pointer to retrieve a value from a JSON document
func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) { func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
return p.get(document, swag.DefaultJSONNameProvider) return p.get(document, swag.DefaultJSONNameProvider)
} }
// Set uses the pointer to set a value from a JSON document // Set uses the pointer to set a value from a JSON document
func (p *Pointer) Set(document interface{}, value interface{}) (interface{}, error) { func (p *Pointer) Set(document any, value any) (any, error) {
return document, p.set(document, value, swag.DefaultJSONNameProvider) return document, p.set(document, value, swag.DefaultJSONNameProvider)
} }
// GetForToken gets a value for a json pointer token 1 level deep // GetForToken gets a value for a json pointer token 1 level deep
func GetForToken(document interface{}, decodedToken string) (interface{}, reflect.Kind, error) { func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider) return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
} }
// SetForToken gets a value for a json pointer token 1 level deep // SetForToken gets a value for a json pointer token 1 level deep
func SetForToken(document interface{}, decodedToken string, value interface{}) (interface{}, error) { func SetForToken(document any, decodedToken string, value any) (any, error) {
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider) return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
} }
func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) { func isNil(input any) bool {
if input == nil {
return true
}
kind := reflect.TypeOf(input).Kind()
switch kind { //nolint:exhaustive
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
return reflect.ValueOf(input).IsNil()
default:
return false
}
}
func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node)) rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind() kind := rValue.Kind()
if isNil(node) {
return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken)
}
if rValue.Type().Implements(jsonPointableType) { switch typed := node.(type) {
r, err := node.(JSONPointable).JSONLookup(decodedToken) case JSONPointable:
r, err := typed.JSONLookup(decodedToken)
if err != nil { if err != nil {
return nil, kind, err return nil, kind, err
} }
return r, kind, nil return r, kind, nil
case *any: // case of a pointer to interface, that is not resolved by reflect.Indirect
return getSingleImpl(*typed, decodedToken, nameProvider)
} }
switch kind { switch kind { //nolint:exhaustive
case reflect.Struct: case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok { if !ok {
@ -159,7 +179,7 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam
} }
func setSingleImpl(node, data interface{}, decodedToken string, nameProvider *swag.NameProvider) error { func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameProvider) error {
rValue := reflect.Indirect(reflect.ValueOf(node)) rValue := reflect.Indirect(reflect.ValueOf(node))
if ns, ok := node.(JSONSetable); ok { // pointer impl if ns, ok := node.(JSONSetable); ok { // pointer impl
@ -170,7 +190,7 @@ func setSingleImpl(node, data interface{}, decodedToken string, nameProvider *sw
return node.(JSONSetable).JSONSet(decodedToken, data) return node.(JSONSetable).JSONSet(decodedToken, data)
} }
switch rValue.Kind() { switch rValue.Kind() { //nolint:exhaustive
case reflect.Struct: case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok { if !ok {
@ -210,7 +230,7 @@ func setSingleImpl(node, data interface{}, decodedToken string, nameProvider *sw
} }
func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) { func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
if nameProvider == nil { if nameProvider == nil {
nameProvider = swag.DefaultJSONNameProvider nameProvider = swag.DefaultJSONNameProvider
@ -231,8 +251,7 @@ func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interf
if err != nil { if err != nil {
return nil, knd, err return nil, knd, err
} }
node, kind = r, knd node = r
} }
rValue := reflect.ValueOf(node) rValue := reflect.ValueOf(node)
@ -241,11 +260,11 @@ func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interf
return node, kind, nil return node, kind, nil
} }
func (p *Pointer) set(node, data interface{}, nameProvider *swag.NameProvider) error { func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error {
knd := reflect.ValueOf(node).Kind() knd := reflect.ValueOf(node).Kind()
if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array { if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
return fmt.Errorf("only structs, pointers, maps and slices are supported for setting values") return errors.New("only structs, pointers, maps and slices are supported for setting values")
} }
if nameProvider == nil { if nameProvider == nil {
@ -284,7 +303,7 @@ func (p *Pointer) set(node, data interface{}, nameProvider *swag.NameProvider) e
continue continue
} }
switch kind { switch kind { //nolint:exhaustive
case reflect.Struct: case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok { if !ok {
@ -363,6 +382,128 @@ func (p *Pointer) String() string {
return pointerString return pointerString
} }
func (p *Pointer) Offset(document string) (int64, error) {
dec := json.NewDecoder(strings.NewReader(document))
var offset int64
for _, ttk := range p.DecodedTokens() {
tk, err := dec.Token()
if err != nil {
return 0, err
}
switch tk := tk.(type) {
case json.Delim:
switch tk {
case '{':
offset, err = offsetSingleObject(dec, ttk)
if err != nil {
return 0, err
}
case '[':
offset, err = offsetSingleArray(dec, ttk)
if err != nil {
return 0, err
}
default:
return 0, fmt.Errorf("invalid token %#v", tk)
}
default:
return 0, fmt.Errorf("invalid token %#v", tk)
}
}
return offset, nil
}
func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
for dec.More() {
offset := dec.InputOffset()
tk, err := dec.Token()
if err != nil {
return 0, err
}
switch tk := tk.(type) {
case json.Delim:
switch tk {
case '{':
if err = drainSingle(dec); err != nil {
return 0, err
}
case '[':
if err = drainSingle(dec); err != nil {
return 0, err
}
}
case string:
if tk == decodedToken {
return offset, nil
}
default:
return 0, fmt.Errorf("invalid token %#v", tk)
}
}
return 0, fmt.Errorf("token reference %q not found", decodedToken)
}
func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
idx, err := strconv.Atoi(decodedToken)
if err != nil {
return 0, fmt.Errorf("token reference %q is not a number: %v", decodedToken, err)
}
var i int
for i = 0; i < idx && dec.More(); i++ {
tk, err := dec.Token()
if err != nil {
return 0, err
}
if delim, isDelim := tk.(json.Delim); isDelim {
switch delim {
case '{':
if err = drainSingle(dec); err != nil {
return 0, err
}
case '[':
if err = drainSingle(dec); err != nil {
return 0, err
}
}
}
}
if !dec.More() {
return 0, fmt.Errorf("token reference %q not found", decodedToken)
}
return dec.InputOffset(), nil
}
// drainSingle drains a single level of object or array.
// The decoder has to guarantee the beginning delim (i.e. '{' or '[') has been consumed.
func drainSingle(dec *json.Decoder) error {
for dec.More() {
tk, err := dec.Token()
if err != nil {
return err
}
if delim, isDelim := tk.(json.Delim); isDelim {
switch delim {
case '{':
if err = drainSingle(dec); err != nil {
return err
}
case '[':
if err = drainSingle(dec); err != nil {
return err
}
}
}
}
// Consumes the ending delim
if _, err := dec.Token(); err != nil {
return err
}
return nil
}
// Specific JSON pointer encoding here // Specific JSON pointer encoding here
// ~0 => ~ // ~0 => ~
// ~1 => / // ~1 => /
@ -377,14 +518,14 @@ func (p *Pointer) String() string {
// Unescape unescapes a json pointer reference token string to the original representation // Unescape unescapes a json pointer reference token string to the original representation
func Unescape(token string) string { func Unescape(token string) string {
step1 := strings.Replace(token, encRefTok1, decRefTok1, -1) step1 := strings.ReplaceAll(token, encRefTok1, decRefTok1)
step2 := strings.Replace(step1, encRefTok0, decRefTok0, -1) step2 := strings.ReplaceAll(step1, encRefTok0, decRefTok0)
return step2 return step2
} }
// Escape escapes a pointer reference token string // Escape escapes a pointer reference token string
func Escape(token string) string { func Escape(token string) string {
step1 := strings.Replace(token, decRefTok0, encRefTok0, -1) step1 := strings.ReplaceAll(token, decRefTok0, encRefTok0)
step2 := strings.Replace(step1, decRefTok1, encRefTok1, -1) step2 := strings.ReplaceAll(step1, decRefTok1, encRefTok1)
return step2 return step2
} }

View file

@ -1,50 +1,61 @@
linters-settings: linters-settings:
govet: govet:
check-shadowing: true check-shadowing: true
golint:
min-confidence: 0
gocyclo: gocyclo:
min-complexity: 30 min-complexity: 45
maligned: maligned:
suggest-new: true suggest-new: true
dupl: dupl:
threshold: 100 threshold: 200
goconst: goconst:
min-len: 2 min-len: 2
min-occurrences: 4 min-occurrences: 3
paralleltest:
ignore-missing: true
linters: linters:
enable-all: true enable-all: true
disable: disable:
- maligned - maligned
- unparam
- lll - lll
- gochecknoinits
- gochecknoglobals - gochecknoglobals
- funlen
- godox - godox
- gocognit - gocognit
- whitespace - whitespace
- wsl - wsl
- funlen
- gochecknoglobals
- gochecknoinits
- scopelint
- wrapcheck - wrapcheck
- exhaustivestruct
- exhaustive
- nlreturn
- testpackage - testpackage
- gci - nlreturn
- gofumpt
- goerr113
- gomnd - gomnd
- tparallel - exhaustivestruct
- goerr113
- errorlint
- nestif - nestif
- godot - godot
- errorlint - gofumpt
- varcheck - paralleltest
- interfacer - tparallel
- deadcode - thelper
- golint
- ifshort - ifshort
- structcheck
- nosnakecase
- varnamelen
- exhaustruct - exhaustruct
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase

View file

@ -1,15 +1,19 @@
# gojsonreference [![Build Status](https://travis-ci.org/go-openapi/jsonreference.svg?branch=master)](https://travis-ci.org/go-openapi/jsonreference) [![codecov](https://codecov.io/gh/go-openapi/jsonreference/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonreference) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) # gojsonreference [![Build Status](https://github.com/go-openapi/jsonreference/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/jsonreference/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/jsonreference/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonreference)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/jsonreference.svg)](https://pkg.go.dev/github.com/go-openapi/jsonreference)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/jsonreference)](https://goreportcard.com/report/github.com/go-openapi/jsonreference)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonreference?status.svg)](http://godoc.org/github.com/go-openapi/jsonreference)
An implementation of JSON Reference - Go language An implementation of JSON Reference - Go language
## Status ## Status
Feature complete. Stable API Feature complete. Stable API
## Dependencies ## Dependencies
https://github.com/go-openapi/jsonpointer * https://github.com/go-openapi/jsonpointer
## References ## References
http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 * http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
* http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03

View file

@ -4,41 +4,58 @@ linters-settings:
golint: golint:
min-confidence: 0 min-confidence: 0
gocyclo: gocyclo:
min-complexity: 30 min-complexity: 45
maligned: maligned:
suggest-new: true suggest-new: true
dupl: dupl:
threshold: 100 threshold: 200
goconst: goconst:
min-len: 2 min-len: 2
min-occurrences: 4 min-occurrences: 3
linters: linters:
enable-all: true enable-all: true
disable: disable:
- maligned - maligned
- unparam
- lll - lll
- gochecknoglobals
- gochecknoinits - gochecknoinits
- gochecknoglobals
- funlen
- godox - godox
- gocognit - gocognit
- whitespace - whitespace
- wsl - wsl
- funlen
- gochecknoglobals
- gochecknoinits
- scopelint
- wrapcheck - wrapcheck
- exhaustivestruct
- exhaustive
- nlreturn
- testpackage - testpackage
- gci - nlreturn
- gofumpt
- goerr113
- gomnd - gomnd
- tparallel - exhaustivestruct
- goerr113
- errorlint
- nestif - nestif
- godot - godot
- errorlint - gofumpt
- paralleltest - paralleltest
- tparallel
- thelper
- ifshort
- exhaustruct
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase

View file

@ -1,4 +1,4 @@
# Loads OAI specs [![Build Status](https://travis-ci.org/go-openapi/loads.svg?branch=master)](https://travis-ci.org/go-openapi/loads) [![codecov](https://codecov.io/gh/go-openapi/loads/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/loads) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![Actions/Go Test Status](https://github.com/go-openapi/loads/workflows/Go%20Test/badge.svg)](https://github.com/go-openapi/loads/actions?query=workflow%3A"Go+Test") # Loads OAI specs [![Build Status](https://github.com/go-openapi/loads/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/loads/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/loads/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/loads)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/loads/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/loads?status.svg)](http://godoc.org/github.com/go-openapi/loads) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/loads/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/loads?status.svg)](http://godoc.org/github.com/go-openapi/loads)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/loads)](https://goreportcard.com/report/github.com/go-openapi/loads) [![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/loads)](https://goreportcard.com/report/github.com/go-openapi/loads)

View file

@ -12,10 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
/* // Package loads provides document loading methods for swagger (OAI) specifications.
Package loads provides document loading methods for swagger (OAI) specifications. //
// It is used by other go-openapi packages to load and run analysis on local or remote spec documents.
It is used by other go-openapi packages to load and run analysis on local or remote spec documents.
*/
package loads package loads

View file

@ -21,7 +21,7 @@
func init() { func init() {
jsonLoader := &loader{ jsonLoader := &loader{
DocLoaderWithMatch: DocLoaderWithMatch{ DocLoaderWithMatch: DocLoaderWithMatch{
Match: func(pth string) bool { Match: func(_ string) bool {
return true return true
}, },
Fn: JSONDoc, Fn: JSONDoc,
@ -86,7 +86,7 @@ func (l *loader) Load(path string) (json.RawMessage, error) {
return nil, erp return nil, erp
} }
var lastErr error = errors.New("no loader matched") // default error if no match was found lastErr := errors.New("no loader matched") // default error if no match was found
for ldr := l; ldr != nil; ldr = ldr.Next { for ldr := l; ldr != nil; ldr = ldr.Next {
if ldr.Match != nil && !ldr.Match(path) { if ldr.Match != nil && !ldr.Match(path) {
continue continue
@ -118,9 +118,8 @@ func JSONDoc(path string) (json.RawMessage, error) {
// This sets the configuration at the package level. // This sets the configuration at the package level.
// //
// NOTE: // NOTE:
// * this updates the default loader used by github.com/go-openapi/spec // - this updates the default loader used by github.com/go-openapi/spec
// * since this sets package level globals, you shouln't call this concurrently // - since this sets package level globals, you shouln't call this concurrently
//
func AddLoader(predicate DocMatcher, load DocLoader) { func AddLoader(predicate DocMatcher, load DocLoader) {
loaders = loaders.WithHead(&loader{ loaders = loaders.WithHead(&loader{
DocLoaderWithMatch: DocLoaderWithMatch{ DocLoaderWithMatch: DocLoaderWithMatch{

View file

@ -38,8 +38,8 @@ type Document struct {
specFilePath string specFilePath string
origSpec *spec.Swagger origSpec *spec.Swagger
schema *spec.Schema schema *spec.Schema
raw json.RawMessage
pathLoader *loader pathLoader *loader
raw json.RawMessage
} }
// JSONSpec loads a spec from a json document // JSONSpec loads a spec from a json document
@ -49,7 +49,14 @@ func JSONSpec(path string, options ...LoaderOption) (*Document, error) {
return nil, err return nil, err
} }
// convert to json // convert to json
return Analyzed(data, "", options...) doc, err := Analyzed(data, "", options...)
if err != nil {
return nil, err
}
doc.specFilePath = path
return doc, nil
} }
// Embedded returns a Document based on embedded specs. No analysis is required // Embedded returns a Document based on embedded specs. No analysis is required
@ -71,7 +78,6 @@ func Embedded(orig, flat json.RawMessage, options ...LoaderOption) (*Document, e
// Spec loads a new spec document from a local or remote path // Spec loads a new spec document from a local or remote path
func Spec(path string, options ...LoaderOption) (*Document, error) { func Spec(path string, options ...LoaderOption) (*Document, error) {
ldr := loaderFromOptions(options) ldr := loaderFromOptions(options)
b, err := ldr.Load(path) b, err := ldr.Load(path)
@ -84,12 +90,10 @@ func Spec(path string, options ...LoaderOption) (*Document, error) {
return nil, err return nil, err
} }
if document != nil {
document.specFilePath = path document.specFilePath = path
document.pathLoader = ldr document.pathLoader = ldr
}
return document, err return document, nil
} }
// Analyzed creates a new analyzed spec document for a root json.RawMessage. // Analyzed creates a new analyzed spec document for a root json.RawMessage.
@ -117,7 +121,7 @@ func Analyzed(data json.RawMessage, version string, options ...LoaderOption) (*D
} }
d := &Document{ d := &Document{
Analyzer: analysis.New(swspec), Analyzer: analysis.New(swspec), // NOTE: at this moment, analysis does not follow $refs to documents outside the root doc
schema: spec.MustLoadSwagger20Schema(), schema: spec.MustLoadSwagger20Schema(),
spec: swspec, spec: swspec,
raw: raw, raw: raw,
@ -152,9 +156,8 @@ func trimData(in json.RawMessage) (json.RawMessage, error) {
return d, nil return d, nil
} }
// Expanded expands the ref fields in the spec document and returns a new spec document // Expanded expands the $ref fields in the spec document and returns a new spec document
func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) { func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
swspec := new(spec.Swagger) swspec := new(spec.Swagger)
if err := json.Unmarshal(d.raw, swspec); err != nil { if err := json.Unmarshal(d.raw, swspec); err != nil {
return nil, err return nil, err
@ -163,6 +166,9 @@ func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
var expandOptions *spec.ExpandOptions var expandOptions *spec.ExpandOptions
if len(options) > 0 { if len(options) > 0 {
expandOptions = options[0] expandOptions = options[0]
if expandOptions.RelativeBase == "" {
expandOptions.RelativeBase = d.specFilePath
}
} else { } else {
expandOptions = &spec.ExpandOptions{ expandOptions = &spec.ExpandOptions{
RelativeBase: d.specFilePath, RelativeBase: d.specFilePath,
@ -194,7 +200,7 @@ func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
return dd, nil return dd, nil
} }
// BasePath the base path for this spec // BasePath the base path for the API specified by this spec
func (d *Document) BasePath() string { func (d *Document) BasePath() string {
return d.spec.BasePath return d.spec.BasePath
} }
@ -242,8 +248,11 @@ func (d *Document) ResetDefinitions() *Document {
// Pristine creates a new pristine document instance based on the input data // Pristine creates a new pristine document instance based on the input data
func (d *Document) Pristine() *Document { func (d *Document) Pristine() *Document {
dd, _ := Analyzed(d.Raw(), d.Version()) raw, _ := json.Marshal(d.Spec())
dd, _ := Analyzed(raw, d.Version())
dd.pathLoader = d.pathLoader dd.pathLoader = d.pathLoader
dd.specFilePath = d.specFilePath
return dd return dd
} }

View file

@ -1,44 +1,62 @@
linters-settings: linters-settings:
govet: govet:
# Using err repeatedly considered as shadowing. check-shadowing: true
check-shadowing: false
golint: golint:
min-confidence: 0 min-confidence: 0
gocyclo: gocyclo:
min-complexity: 30 min-complexity: 45
maligned: maligned:
suggest-new: true suggest-new: true
dupl: dupl:
threshold: 100 threshold: 200
goconst: goconst:
min-len: 2 min-len: 2
min-occurrences: 4 min-occurrences: 3
linters: linters:
enable-all: true
disable: disable:
- nilerr # nilerr crashes on this repo
- maligned - maligned
- unparam
- lll - lll
- gochecknoinits
- gochecknoglobals - gochecknoglobals
- funlen
- godox - godox
- gocognit - gocognit
- whitespace - whitespace
- wsl - wsl
- funlen
- gochecknoglobals
- gochecknoinits
- scopelint
- wrapcheck - wrapcheck
- exhaustivestruct
- exhaustive
- nlreturn
- testpackage - testpackage
- gci - nlreturn
- gofumpt
- goerr113
- gomnd - gomnd
- tparallel - exhaustivestruct
- goerr113
- errorlint
- nestif - nestif
- godot - godot
- errorlint - gofumpt
- noctx - paralleltest
- tparallel
- thelper
- ifshort
- exhaustruct
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer - interfacer
- nilerr - scopelint
- varcheck
- structcheck
- golint
- nosnakecase

View file

@ -1,7 +1,10 @@
# runtime [![Build Status](https://travis-ci.org/go-openapi/runtime.svg?branch=client-context)](https://travis-ci.org/go-openapi/runtime) [![codecov](https://codecov.io/gh/go-openapi/runtime/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/runtime) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) # runtime [![Build Status](https://github.com/go-openapi/runtime/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/runtime/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/runtime/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/runtime)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/runtime/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/runtime?status.svg)](http://godoc.org/github.com/go-openapi/runtime) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/runtime/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/runtime.svg)](https://pkg.go.dev/github.com/go-openapi/runtime)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/runtime)](https://goreportcard.com/report/github.com/go-openapi/runtime)
# golang Open-API toolkit - runtime # go OpenAPI toolkit runtime
The runtime component for use in codegeneration or as untyped usage. The runtime component for use in code generation or as untyped usage.

View file

@ -38,9 +38,16 @@ type byteStreamOpts struct {
Close bool Close bool
} }
// ByteStreamConsumer creates a consumer for byte streams, // ByteStreamConsumer creates a consumer for byte streams.
// takes a Writer/BinaryUnmarshaler interface or binary slice by reference, //
// and reads from the provided reader // The consumer consumes from a provided reader into the data passed by reference.
//
// Supported output underlying types and interfaces, prioritized in this order:
// - io.ReaderFrom (for maximum control)
// - io.Writer (performs io.Copy)
// - encoding.BinaryUnmarshaler
// - *string
// - *[]byte
func ByteStreamConsumer(opts ...byteStreamOpt) Consumer { func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
var vals byteStreamOpts var vals byteStreamOpts
for _, opt := range opts { for _, opt := range opts {
@ -51,44 +58,70 @@ func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
if reader == nil { if reader == nil {
return errors.New("ByteStreamConsumer requires a reader") // early exit return errors.New("ByteStreamConsumer requires a reader") // early exit
} }
if data == nil {
return errors.New("nil destination for ByteStreamConsumer")
}
close := defaultCloser closer := defaultCloser
if vals.Close { if vals.Close {
if cl, ok := reader.(io.Closer); ok { if cl, isReaderCloser := reader.(io.Closer); isReaderCloser {
close = cl.Close closer = cl.Close
} }
} }
//nolint:errcheck // closing a reader wouldn't fail. defer func() {
defer close() _ = closer()
}()
if wrtr, ok := data.(io.Writer); ok { if readerFrom, isReaderFrom := data.(io.ReaderFrom); isReaderFrom {
_, err := io.Copy(wrtr, reader) _, err := readerFrom.ReadFrom(reader)
return err return err
} }
buf := new(bytes.Buffer) if writer, isDataWriter := data.(io.Writer); isDataWriter {
_, err := io.Copy(writer, reader)
return err
}
// buffers input before writing to data
var buf bytes.Buffer
_, err := buf.ReadFrom(reader) _, err := buf.ReadFrom(reader)
if err != nil { if err != nil {
return err return err
} }
b := buf.Bytes() b := buf.Bytes()
if bu, ok := data.(encoding.BinaryUnmarshaler); ok { switch destinationPointer := data.(type) {
return bu.UnmarshalBinary(b) case encoding.BinaryUnmarshaler:
} return destinationPointer.UnmarshalBinary(b)
case *any:
switch (*destinationPointer).(type) {
case string:
*destinationPointer = string(b)
return nil
case []byte:
*destinationPointer = b
if data != nil {
if str, ok := data.(*string); ok {
*str = string(b)
return nil return nil
} }
default:
// check for the underlying type to be pointer to []byte or string,
if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Ptr {
return errors.New("destination must be a pointer")
} }
if t := reflect.TypeOf(data); data != nil && t.Kind() == reflect.Ptr {
v := reflect.Indirect(reflect.ValueOf(data)) v := reflect.Indirect(reflect.ValueOf(data))
if t = v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { t := v.Type()
switch {
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
v.SetBytes(b) v.SetBytes(b)
return nil return nil
case t.Kind() == reflect.String:
v.SetString(string(b))
return nil
} }
} }
@ -97,67 +130,87 @@ func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
}) })
} }
// ByteStreamProducer creates a producer for byte streams, // ByteStreamProducer creates a producer for byte streams.
// takes a Reader/BinaryMarshaler interface or binary slice, //
// and writes to a writer (essentially a pipe) // The producer takes input data then writes to an output writer (essentially as a pipe).
//
// Supported input underlying types and interfaces, prioritized in this order:
// - io.WriterTo (for maximum control)
// - io.Reader (performs io.Copy). A ReadCloser is closed before exiting.
// - encoding.BinaryMarshaler
// - error (writes as a string)
// - []byte
// - string
// - struct, other slices: writes as JSON
func ByteStreamProducer(opts ...byteStreamOpt) Producer { func ByteStreamProducer(opts ...byteStreamOpt) Producer {
var vals byteStreamOpts var vals byteStreamOpts
for _, opt := range opts { for _, opt := range opts {
opt(&vals) opt(&vals)
} }
return ProducerFunc(func(writer io.Writer, data interface{}) error { return ProducerFunc(func(writer io.Writer, data interface{}) error {
if writer == nil { if writer == nil {
return errors.New("ByteStreamProducer requires a writer") // early exit return errors.New("ByteStreamProducer requires a writer") // early exit
} }
close := defaultCloser if data == nil {
if vals.Close { return errors.New("nil data for ByteStreamProducer")
if cl, ok := writer.(io.Closer); ok {
close = cl.Close
} }
}
//nolint:errcheck // TODO: closing a writer would fail.
defer close()
if rc, ok := data.(io.ReadCloser); ok { closer := defaultCloser
if vals.Close {
if cl, isWriterCloser := writer.(io.Closer); isWriterCloser {
closer = cl.Close
}
}
defer func() {
_ = closer()
}()
if rc, isDataCloser := data.(io.ReadCloser); isDataCloser {
defer rc.Close() defer rc.Close()
} }
if rdr, ok := data.(io.Reader); ok { switch origin := data.(type) {
_, err := io.Copy(writer, rdr) case io.WriterTo:
_, err := origin.WriteTo(writer)
return err return err
}
if bm, ok := data.(encoding.BinaryMarshaler); ok { case io.Reader:
bytes, err := bm.MarshalBinary() _, err := io.Copy(writer, origin)
return err
case encoding.BinaryMarshaler:
bytes, err := origin.MarshalBinary()
if err != nil { if err != nil {
return err return err
} }
_, err = writer.Write(bytes) _, err = writer.Write(bytes)
return err return err
}
if data != nil { case error:
if str, ok := data.(string); ok { _, err := writer.Write([]byte(origin.Error()))
_, err := writer.Write([]byte(str))
return err return err
}
if e, ok := data.(error); ok {
_, err := writer.Write([]byte(e.Error()))
return err
}
default:
v := reflect.Indirect(reflect.ValueOf(data)) v := reflect.Indirect(reflect.ValueOf(data))
if t := v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { t := v.Type()
switch {
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
_, err := writer.Write(v.Bytes()) _, err := writer.Write(v.Bytes())
return err return err
}
if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice { case t.Kind() == reflect.String:
_, err := writer.Write([]byte(v.String()))
return err
case t.Kind() == reflect.Struct || t.Kind() == reflect.Slice:
b, err := swag.WriteJSON(data) b, err := swag.WriteJSON(data)
if err != nil { if err != nil {
return err return err
} }
_, err = writer.Write(b) _, err = writer.Write(b)
return err return err
} }

View file

@ -30,12 +30,12 @@ type ClientOperation struct {
AuthInfo ClientAuthInfoWriter AuthInfo ClientAuthInfoWriter
Params ClientRequestWriter Params ClientRequestWriter
Reader ClientResponseReader Reader ClientResponseReader
Context context.Context Context context.Context //nolint:containedctx // we precisely want this type to contain the request context
Client *http.Client Client *http.Client
} }
// A ClientTransport implementor knows how to submit Request objects to some destination // A ClientTransport implementor knows how to submit Request objects to some destination
type ClientTransport interface { type ClientTransport interface {
//Submit(string, RequestWriter, ResponseReader, AuthInfoWriter) (interface{}, error) // Submit(string, RequestWriter, ResponseReader, AuthInfoWriter) (interface{}, error)
Submit(*ClientOperation) (interface{}, error) Submit(*ClientOperation) (interface{}, error)
} }

View file

@ -37,8 +37,8 @@ type ClientRequestWriter interface {
} }
// ClientRequest is an interface for things that know how to // ClientRequest is an interface for things that know how to
// add information to a swagger client request // add information to a swagger client request.
type ClientRequest interface { type ClientRequest interface { //nolint:interfacebloat // a swagger-capable request is quite rich, hence the many getter/setters
SetHeaderParam(string, ...string) error SetHeaderParam(string, ...string) error
GetHeaderParams() http.Header GetHeaderParams() http.Header

View file

@ -16,62 +16,335 @@
import ( import (
"bytes" "bytes"
"context"
"encoding"
"encoding/csv" "encoding/csv"
"errors" "errors"
"fmt"
"io" "io"
"reflect"
"golang.org/x/sync/errgroup"
) )
// CSVConsumer creates a new CSV consumer // CSVConsumer creates a new CSV consumer.
func CSVConsumer() Consumer { //
// The consumer consumes CSV records from a provided reader into the data passed by reference.
//
// CSVOpts options may be specified to alter the default CSV behavior on the reader and the writer side (e.g. separator, skip header, ...).
// The defaults are those of the standard library's csv.Reader and csv.Writer.
//
// Supported output underlying types and interfaces, prioritized in this order:
// - *csv.Writer
// - CSVWriter (writer options are ignored)
// - io.Writer (as raw bytes)
// - io.ReaderFrom (as raw bytes)
// - encoding.BinaryUnmarshaler (as raw bytes)
// - *[][]string (as a collection of records)
// - *[]byte (as raw bytes)
// - *string (a raw bytes)
//
// The consumer prioritizes situations where buffering the input is not required.
func CSVConsumer(opts ...CSVOpt) Consumer {
o := csvOptsWithDefaults(opts)
return ConsumerFunc(func(reader io.Reader, data interface{}) error { return ConsumerFunc(func(reader io.Reader, data interface{}) error {
if reader == nil { if reader == nil {
return errors.New("CSVConsumer requires a reader") return errors.New("CSVConsumer requires a reader")
} }
if data == nil {
return errors.New("nil destination for CSVConsumer")
}
csvReader := csv.NewReader(reader) csvReader := csv.NewReader(reader)
writer, ok := data.(io.Writer) o.applyToReader(csvReader)
if !ok { closer := defaultCloser
return errors.New("data type must be io.Writer") if o.closeStream {
if cl, isReaderCloser := reader.(io.Closer); isReaderCloser {
closer = cl.Close
} }
csvWriter := csv.NewWriter(writer) }
records, err := csvReader.ReadAll() defer func() {
if err != nil { _ = closer()
}()
switch destination := data.(type) {
case *csv.Writer:
csvWriter := destination
o.applyToWriter(csvWriter)
return pipeCSV(csvWriter, csvReader, o)
case CSVWriter:
csvWriter := destination
// no writer options available
return pipeCSV(csvWriter, csvReader, o)
case io.Writer:
csvWriter := csv.NewWriter(destination)
o.applyToWriter(csvWriter)
return pipeCSV(csvWriter, csvReader, o)
case io.ReaderFrom:
var buf bytes.Buffer
csvWriter := csv.NewWriter(&buf)
o.applyToWriter(csvWriter)
if err := bufferedCSV(csvWriter, csvReader, o); err != nil {
return err return err
} }
for _, r := range records { _, err := destination.ReadFrom(&buf)
if err := csvWriter.Write(r); err != nil {
return err
case encoding.BinaryUnmarshaler:
var buf bytes.Buffer
csvWriter := csv.NewWriter(&buf)
o.applyToWriter(csvWriter)
if err := bufferedCSV(csvWriter, csvReader, o); err != nil {
return err return err
} }
return destination.UnmarshalBinary(buf.Bytes())
default:
// support *[][]string, *[]byte, *string
if ptr := reflect.TypeOf(data); ptr.Kind() != reflect.Ptr {
return errors.New("destination must be a pointer")
} }
csvWriter.Flush()
v := reflect.Indirect(reflect.ValueOf(data))
t := v.Type()
switch {
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Slice && t.Elem().Elem().Kind() == reflect.String:
csvWriter := &csvRecordsWriter{}
// writer options are ignored
if err := pipeCSV(csvWriter, csvReader, o); err != nil {
return err
}
v.Grow(len(csvWriter.records))
v.SetCap(len(csvWriter.records)) // in case Grow was unnessary, trim down the capacity
v.SetLen(len(csvWriter.records))
reflect.Copy(v, reflect.ValueOf(csvWriter.records))
return nil return nil
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
var buf bytes.Buffer
csvWriter := csv.NewWriter(&buf)
o.applyToWriter(csvWriter)
if err := bufferedCSV(csvWriter, csvReader, o); err != nil {
return err
}
v.SetBytes(buf.Bytes())
return nil
case t.Kind() == reflect.String:
var buf bytes.Buffer
csvWriter := csv.NewWriter(&buf)
o.applyToWriter(csvWriter)
if err := bufferedCSV(csvWriter, csvReader, o); err != nil {
return err
}
v.SetString(buf.String())
return nil
default:
return fmt.Errorf("%v (%T) is not supported by the CSVConsumer, %s",
data, data, "can be resolved by supporting CSVWriter/Writer/BinaryUnmarshaler interface",
)
}
}
}) })
} }
// CSVProducer creates a new CSV producer // CSVProducer creates a new CSV producer.
func CSVProducer() Producer { //
// The producer takes input data then writes as CSV to an output writer (essentially as a pipe).
//
// Supported input underlying types and interfaces, prioritized in this order:
// - *csv.Reader
// - CSVReader (reader options are ignored)
// - io.Reader
// - io.WriterTo
// - encoding.BinaryMarshaler
// - [][]string
// - []byte
// - string
//
// The producer prioritizes situations where buffering the input is not required.
func CSVProducer(opts ...CSVOpt) Producer {
o := csvOptsWithDefaults(opts)
return ProducerFunc(func(writer io.Writer, data interface{}) error { return ProducerFunc(func(writer io.Writer, data interface{}) error {
if writer == nil { if writer == nil {
return errors.New("CSVProducer requires a writer") return errors.New("CSVProducer requires a writer")
} }
if data == nil {
dataBytes, ok := data.([]byte) return errors.New("nil data for CSVProducer")
if !ok { }
return errors.New("data type must be byte array")
csvWriter := csv.NewWriter(writer)
o.applyToWriter(csvWriter)
closer := defaultCloser
if o.closeStream {
if cl, isWriterCloser := writer.(io.Closer); isWriterCloser {
closer = cl.Close
}
}
defer func() {
_ = closer()
}()
if rc, isDataCloser := data.(io.ReadCloser); isDataCloser {
defer rc.Close()
}
switch origin := data.(type) {
case *csv.Reader:
csvReader := origin
o.applyToReader(csvReader)
return pipeCSV(csvWriter, csvReader, o)
case CSVReader:
csvReader := origin
// no reader options available
return pipeCSV(csvWriter, csvReader, o)
case io.Reader:
csvReader := csv.NewReader(origin)
o.applyToReader(csvReader)
return pipeCSV(csvWriter, csvReader, o)
case io.WriterTo:
// async piping of the writes performed by WriteTo
r, w := io.Pipe()
csvReader := csv.NewReader(r)
o.applyToReader(csvReader)
pipe, _ := errgroup.WithContext(context.Background())
pipe.Go(func() error {
_, err := origin.WriteTo(w)
_ = w.Close()
return err
})
pipe.Go(func() error {
defer func() {
_ = r.Close()
}()
return pipeCSV(csvWriter, csvReader, o)
})
return pipe.Wait()
case encoding.BinaryMarshaler:
buf, err := origin.MarshalBinary()
if err != nil {
return err
}
rdr := bytes.NewBuffer(buf)
csvReader := csv.NewReader(rdr)
return bufferedCSV(csvWriter, csvReader, o)
default:
// support [][]string, []byte, string (or pointers to those)
v := reflect.Indirect(reflect.ValueOf(data))
t := v.Type()
switch {
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Slice && t.Elem().Elem().Kind() == reflect.String:
csvReader := &csvRecordsWriter{
records: make([][]string, v.Len()),
}
reflect.Copy(reflect.ValueOf(csvReader.records), v)
return pipeCSV(csvWriter, csvReader, o)
case t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8:
buf := bytes.NewBuffer(v.Bytes())
csvReader := csv.NewReader(buf)
o.applyToReader(csvReader)
return bufferedCSV(csvWriter, csvReader, o)
case t.Kind() == reflect.String:
buf := bytes.NewBufferString(v.String())
csvReader := csv.NewReader(buf)
o.applyToReader(csvReader)
return bufferedCSV(csvWriter, csvReader, o)
default:
return fmt.Errorf("%v (%T) is not supported by the CSVProducer, %s",
data, data, "can be resolved by supporting CSVReader/Reader/BinaryMarshaler interface",
)
}
}
})
}
// pipeCSV copies CSV records from a CSV reader to a CSV writer
func pipeCSV(csvWriter CSVWriter, csvReader CSVReader, opts csvOpts) error {
for ; opts.skippedLines > 0; opts.skippedLines-- {
_, err := csvReader.Read()
if err != nil {
if errors.Is(err, io.EOF) {
return nil
}
return err
}
}
for {
record, err := csvReader.Read()
if err != nil {
if errors.Is(err, io.EOF) {
break
}
return err
}
if err := csvWriter.Write(record); err != nil {
return err
}
}
csvWriter.Flush()
return csvWriter.Error()
}
// bufferedCSV copies CSV records from a CSV reader to a CSV writer,
// by first reading all records then writing them at once.
func bufferedCSV(csvWriter *csv.Writer, csvReader *csv.Reader, opts csvOpts) error {
for ; opts.skippedLines > 0; opts.skippedLines-- {
_, err := csvReader.Read()
if err != nil {
if errors.Is(err, io.EOF) {
return nil
}
return err
}
} }
csvReader := csv.NewReader(bytes.NewBuffer(dataBytes))
records, err := csvReader.ReadAll() records, err := csvReader.ReadAll()
if err != nil { if err != nil {
return err return err
} }
csvWriter := csv.NewWriter(writer)
for _, r := range records { return csvWriter.WriteAll(records)
if err := csvWriter.Write(r); err != nil {
return err
}
}
csvWriter.Flush()
return nil
})
} }

121
vendor/github.com/go-openapi/runtime/csv_options.go generated vendored Normal file
View file

@ -0,0 +1,121 @@
package runtime
import (
"encoding/csv"
"io"
)
// CSVOpts alter the behavior of the CSV consumer or producer.
type CSVOpt func(*csvOpts)
type csvOpts struct {
csvReader csv.Reader
csvWriter csv.Writer
skippedLines int
closeStream bool
}
// WithCSVReaderOpts specifies the options to csv.Reader
// when reading CSV.
func WithCSVReaderOpts(reader csv.Reader) CSVOpt {
return func(o *csvOpts) {
o.csvReader = reader
}
}
// WithCSVWriterOpts specifies the options to csv.Writer
// when writing CSV.
func WithCSVWriterOpts(writer csv.Writer) CSVOpt {
return func(o *csvOpts) {
o.csvWriter = writer
}
}
// WithCSVSkipLines will skip header lines.
func WithCSVSkipLines(skipped int) CSVOpt {
return func(o *csvOpts) {
o.skippedLines = skipped
}
}
func WithCSVClosesStream() CSVOpt {
return func(o *csvOpts) {
o.closeStream = true
}
}
func (o csvOpts) applyToReader(in *csv.Reader) {
if o.csvReader.Comma != 0 {
in.Comma = o.csvReader.Comma
}
if o.csvReader.Comment != 0 {
in.Comment = o.csvReader.Comment
}
if o.csvReader.FieldsPerRecord != 0 {
in.FieldsPerRecord = o.csvReader.FieldsPerRecord
}
in.LazyQuotes = o.csvReader.LazyQuotes
in.TrimLeadingSpace = o.csvReader.TrimLeadingSpace
in.ReuseRecord = o.csvReader.ReuseRecord
}
func (o csvOpts) applyToWriter(in *csv.Writer) {
if o.csvWriter.Comma != 0 {
in.Comma = o.csvWriter.Comma
}
in.UseCRLF = o.csvWriter.UseCRLF
}
func csvOptsWithDefaults(opts []CSVOpt) csvOpts {
var o csvOpts
for _, apply := range opts {
apply(&o)
}
return o
}
type CSVWriter interface {
Write([]string) error
Flush()
Error() error
}
type CSVReader interface {
Read() ([]string, error)
}
var (
_ CSVWriter = &csvRecordsWriter{}
_ CSVReader = &csvRecordsWriter{}
)
// csvRecordsWriter is an internal container to move CSV records back and forth
type csvRecordsWriter struct {
i int
records [][]string
}
func (w *csvRecordsWriter) Write(record []string) error {
w.records = append(w.records, record)
return nil
}
func (w *csvRecordsWriter) Read() ([]string, error) {
if w.i >= len(w.records) {
return nil, io.EOF
}
defer func() {
w.i++
}()
return w.records[w.i], nil
}
func (w *csvRecordsWriter) Flush() {}
func (w *csvRecordsWriter) Error() error {
return nil
}

View file

@ -5,6 +5,8 @@
"os" "os"
) )
var _ Logger = StandardLogger{}
type StandardLogger struct{} type StandardLogger struct{}
func (StandardLogger) Printf(format string, args ...interface{}) { func (StandardLogger) Printf(format string, args ...interface{}) {

View file

@ -18,6 +18,8 @@
stdContext "context" stdContext "context"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"path"
"strings" "strings"
"sync" "sync"
@ -35,12 +37,21 @@
// Debug when true turns on verbose logging // Debug when true turns on verbose logging
var Debug = logger.DebugEnabled() var Debug = logger.DebugEnabled()
// Logger is the standard libray logger used for printing debug messages
var Logger logger.Logger = logger.StandardLogger{} var Logger logger.Logger = logger.StandardLogger{}
func debugLog(format string, args ...interface{}) { func debugLogfFunc(lg logger.Logger) func(string, ...any) {
if Debug { if logger.DebugEnabled() {
Logger.Printf(format, args...) if lg == nil {
return Logger.Debugf
} }
return lg.Debugf
}
// muted logger
return func(_ string, _ ...any) {}
} }
// A Builder can create middlewares // A Builder can create middlewares
@ -77,6 +88,7 @@ type Context struct {
analyzer *analysis.Spec analyzer *analysis.Spec
api RoutableAPI api RoutableAPI
router Router router Router
debugLogf func(string, ...any) // a logging function to debug context and all components using it
} }
type routableUntypedAPI struct { type routableUntypedAPI struct {
@ -162,7 +174,7 @@ func (r *routableUntypedAPI) HandlerFor(method, path string) (http.Handler, bool
r.hlock.Unlock() r.hlock.Unlock()
return handler, ok return handler, ok
} }
func (r *routableUntypedAPI) ServeErrorFor(operationID string) func(http.ResponseWriter, *http.Request, error) { func (r *routableUntypedAPI) ServeErrorFor(_ string) func(http.ResponseWriter, *http.Request, error) {
return r.api.ServeError return r.api.ServeError
} }
func (r *routableUntypedAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer { func (r *routableUntypedAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
@ -189,7 +201,9 @@ func (r *routableUntypedAPI) DefaultConsumes() string {
return r.defaultConsumes return r.defaultConsumes
} }
// NewRoutableContext creates a new context for a routable API // NewRoutableContext creates a new context for a routable API.
//
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context { func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context {
var an *analysis.Spec var an *analysis.Spec
if spec != nil { if spec != nil {
@ -199,26 +213,40 @@ func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Ro
return NewRoutableContextWithAnalyzedSpec(spec, an, routableAPI, routes) return NewRoutableContextWithAnalyzedSpec(spec, an, routableAPI, routes)
} }
// NewRoutableContextWithAnalyzedSpec is like NewRoutableContext but takes in input the analysed spec too // NewRoutableContextWithAnalyzedSpec is like NewRoutableContext but takes as input an already analysed spec.
//
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
func NewRoutableContextWithAnalyzedSpec(spec *loads.Document, an *analysis.Spec, routableAPI RoutableAPI, routes Router) *Context { func NewRoutableContextWithAnalyzedSpec(spec *loads.Document, an *analysis.Spec, routableAPI RoutableAPI, routes Router) *Context {
// Either there are no spec doc and analysis, or both of them. // Either there are no spec doc and analysis, or both of them.
if !((spec == nil && an == nil) || (spec != nil && an != nil)) { if !((spec == nil && an == nil) || (spec != nil && an != nil)) {
panic(errors.New(http.StatusInternalServerError, "routable context requires either both spec doc and analysis, or none of them")) panic(errors.New(http.StatusInternalServerError, "routable context requires either both spec doc and analysis, or none of them"))
} }
ctx := &Context{spec: spec, api: routableAPI, analyzer: an, router: routes} return &Context{
return ctx spec: spec,
api: routableAPI,
analyzer: an,
router: routes,
debugLogf: debugLogfFunc(nil),
}
} }
// NewContext creates a new context wrapper // NewContext creates a new context wrapper.
//
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context { func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context {
var an *analysis.Spec var an *analysis.Spec
if spec != nil { if spec != nil {
an = analysis.New(spec.Spec()) an = analysis.New(spec.Spec())
} }
ctx := &Context{spec: spec, analyzer: an} ctx := &Context{
spec: spec,
analyzer: an,
router: routes,
debugLogf: debugLogfFunc(nil),
}
ctx.api = newRoutableUntypedAPI(spec, api, ctx) ctx.api = newRoutableUntypedAPI(spec, api, ctx)
ctx.router = routes
return ctx return ctx
} }
@ -282,6 +310,13 @@ func (c *Context) BasePath() string {
return c.spec.BasePath() return c.spec.BasePath()
} }
// SetLogger allows for injecting a logger to catch debug entries.
//
// The logger is enabled in DEBUG mode only.
func (c *Context) SetLogger(lg logger.Logger) {
c.debugLogf = debugLogfFunc(lg)
}
// RequiredProduces returns the accepted content types for responses // RequiredProduces returns the accepted content types for responses
func (c *Context) RequiredProduces() []string { func (c *Context) RequiredProduces() []string {
return c.analyzer.RequiredProduces() return c.analyzer.RequiredProduces()
@ -299,6 +334,7 @@ func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, b
if err != nil { if err != nil {
res = append(res, err) res = append(res, err)
} else { } else {
c.debugLogf("validating content type for %q against [%s]", ct, strings.Join(route.Consumes, ", "))
if err := validateContentType(route.Consumes, ct); err != nil { if err := validateContentType(route.Consumes, ct); err != nil {
res = append(res, err) res = append(res, err)
} }
@ -397,16 +433,16 @@ func (c *Context) ResponseFormat(r *http.Request, offers []string) (string, *htt
var rCtx = r.Context() var rCtx = r.Context()
if v, ok := rCtx.Value(ctxResponseFormat).(string); ok { if v, ok := rCtx.Value(ctxResponseFormat).(string); ok {
debugLog("[%s %s] found response format %q in context", r.Method, r.URL.Path, v) c.debugLogf("[%s %s] found response format %q in context", r.Method, r.URL.Path, v)
return v, r return v, r
} }
format := NegotiateContentType(r, offers, "") format := NegotiateContentType(r, offers, "")
if format != "" { if format != "" {
debugLog("[%s %s] set response format %q in context", r.Method, r.URL.Path, format) c.debugLogf("[%s %s] set response format %q in context", r.Method, r.URL.Path, format)
r = r.WithContext(stdContext.WithValue(rCtx, ctxResponseFormat, format)) r = r.WithContext(stdContext.WithValue(rCtx, ctxResponseFormat, format))
} }
debugLog("[%s %s] negotiated response format %q", r.Method, r.URL.Path, format) c.debugLogf("[%s %s] negotiated response format %q", r.Method, r.URL.Path, format)
return format, r return format, r
} }
@ -469,7 +505,7 @@ func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute)
var rCtx = request.Context() var rCtx = request.Context()
if v, ok := rCtx.Value(ctxBoundParams).(*validation); ok { if v, ok := rCtx.Value(ctxBoundParams).(*validation); ok {
debugLog("got cached validation (valid: %t)", len(v.result) == 0) c.debugLogf("got cached validation (valid: %t)", len(v.result) == 0)
if len(v.result) > 0 { if len(v.result) > 0 {
return v.bound, request, errors.CompositeValidationError(v.result...) return v.bound, request, errors.CompositeValidationError(v.result...)
} }
@ -481,7 +517,7 @@ func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute)
if len(result.result) > 0 { if len(result.result) > 0 {
return result.bound, request, errors.CompositeValidationError(result.result...) return result.bound, request, errors.CompositeValidationError(result.result...)
} }
debugLog("no validation errors found") c.debugLogf("no validation errors found")
return result.bound, request, nil return result.bound, request, nil
} }
@ -492,7 +528,7 @@ func (c *Context) NotFound(rw http.ResponseWriter, r *http.Request) {
// Respond renders the response after doing some content negotiation // Respond renders the response after doing some content negotiation
func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []string, route *MatchedRoute, data interface{}) { func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []string, route *MatchedRoute, data interface{}) {
debugLog("responding to %s %s with produces: %v", r.Method, r.URL.Path, produces) c.debugLogf("responding to %s %s with produces: %v", r.Method, r.URL.Path, produces)
offers := []string{} offers := []string{}
for _, mt := range produces { for _, mt := range produces {
if mt != c.api.DefaultProduces() { if mt != c.api.DefaultProduces() {
@ -501,7 +537,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
} }
// the default producer is last so more specific producers take precedence // the default producer is last so more specific producers take precedence
offers = append(offers, c.api.DefaultProduces()) offers = append(offers, c.api.DefaultProduces())
debugLog("offers: %v", offers) c.debugLogf("offers: %v", offers)
var format string var format string
format, r = c.ResponseFormat(r, offers) format, r = c.ResponseFormat(r, offers)
@ -516,7 +552,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()})) prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
pr, ok := prods[c.api.DefaultProduces()] pr, ok := prods[c.api.DefaultProduces()]
if !ok { if !ok {
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format)) panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
} }
prod = pr prod = pr
} }
@ -542,14 +578,14 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
} }
if route == nil || route.Operation == nil { if route == nil || route.Operation == nil {
rw.WriteHeader(200) rw.WriteHeader(http.StatusOK)
if r.Method == "HEAD" { if r.Method == http.MethodHead {
return return
} }
producers := c.api.ProducersFor(normalizeOffers(offers)) producers := c.api.ProducersFor(normalizeOffers(offers))
prod, ok := producers[format] prod, ok := producers[format]
if !ok { if !ok {
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format)) panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
} }
if err := prod.Produce(rw, data); err != nil { if err := prod.Produce(rw, data); err != nil {
panic(err) // let the recovery middleware deal with this panic(err) // let the recovery middleware deal with this
@ -559,7 +595,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
if _, code, ok := route.Operation.SuccessResponse(); ok { if _, code, ok := route.Operation.SuccessResponse(); ok {
rw.WriteHeader(code) rw.WriteHeader(code)
if code == 204 || r.Method == "HEAD" { if code == http.StatusNoContent || r.Method == http.MethodHead {
return return
} }
@ -570,7 +606,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()})) prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
pr, ok := prods[c.api.DefaultProduces()] pr, ok := prods[c.api.DefaultProduces()]
if !ok { if !ok {
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format)) panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
} }
prod = pr prod = pr
} }
@ -584,45 +620,92 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
c.api.ServeErrorFor(route.Operation.ID)(rw, r, errors.New(http.StatusInternalServerError, "can't produce response")) c.api.ServeErrorFor(route.Operation.ID)(rw, r, errors.New(http.StatusInternalServerError, "can't produce response"))
} }
func (c *Context) APIHandlerSwaggerUI(builder Builder) http.Handler { // APIHandlerSwaggerUI returns a handler to serve the API.
//
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
// A spec UI (SwaggerUI) is served at {API base path}/docs and the spec document at /swagger.json
// (these can be modified with uiOptions).
func (c *Context) APIHandlerSwaggerUI(builder Builder, opts ...UIOption) http.Handler {
b := builder b := builder
if b == nil { if b == nil {
b = PassthroughBuilder b = PassthroughBuilder
} }
var title string specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
sp := c.spec.Spec() var swaggerUIOpts SwaggerUIOpts
if sp != nil && sp.Info != nil && sp.Info.Title != "" { fromCommonToAnyOptions(uiOpts, &swaggerUIOpts)
title = sp.Info.Title
}
swaggerUIOpts := SwaggerUIOpts{ return Spec(specPath, c.spec.Raw(), SwaggerUI(swaggerUIOpts, c.RoutesHandler(b)), specOpts...)
BasePath: c.BasePath(),
Title: title,
}
return Spec("", c.spec.Raw(), SwaggerUI(swaggerUIOpts, c.RoutesHandler(b)))
} }
// APIHandler returns a handler to serve the API, this includes a swagger spec, router and the contract defined in the swagger spec // APIHandlerRapiDoc returns a handler to serve the API.
func (c *Context) APIHandler(builder Builder) http.Handler { //
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
// A spec UI (RapiDoc) is served at {API base path}/docs and the spec document at /swagger.json
// (these can be modified with uiOptions).
func (c *Context) APIHandlerRapiDoc(builder Builder, opts ...UIOption) http.Handler {
b := builder b := builder
if b == nil { if b == nil {
b = PassthroughBuilder b = PassthroughBuilder
} }
specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
var rapidocUIOpts RapiDocOpts
fromCommonToAnyOptions(uiOpts, &rapidocUIOpts)
return Spec(specPath, c.spec.Raw(), RapiDoc(rapidocUIOpts, c.RoutesHandler(b)), specOpts...)
}
// APIHandler returns a handler to serve the API.
//
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
// A spec UI (Redoc) is served at {API base path}/docs and the spec document at /swagger.json
// (these can be modified with uiOptions).
func (c *Context) APIHandler(builder Builder, opts ...UIOption) http.Handler {
b := builder
if b == nil {
b = PassthroughBuilder
}
specPath, uiOpts, specOpts := c.uiOptionsForHandler(opts)
var redocOpts RedocOpts
fromCommonToAnyOptions(uiOpts, &redocOpts)
return Spec(specPath, c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b)), specOpts...)
}
func (c Context) uiOptionsForHandler(opts []UIOption) (string, uiOptions, []SpecOption) {
var title string var title string
sp := c.spec.Spec() sp := c.spec.Spec()
if sp != nil && sp.Info != nil && sp.Info.Title != "" { if sp != nil && sp.Info != nil && sp.Info.Title != "" {
title = sp.Info.Title title = sp.Info.Title
} }
redocOpts := RedocOpts{ // default options (may be overridden)
BasePath: c.BasePath(), optsForContext := []UIOption{
Title: title, WithUIBasePath(c.BasePath()),
WithUITitle(title),
}
optsForContext = append(optsForContext, opts...)
uiOpts := uiOptionsWithDefaults(optsForContext)
// If spec URL is provided, there is a non-default path to serve the spec.
// This makes sure that the UI middleware is aligned with the Spec middleware.
u, _ := url.Parse(uiOpts.SpecURL)
var specPath string
if u != nil {
specPath = u.Path
} }
return Spec("", c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b))) pth, doc := path.Split(specPath)
if pth == "." {
pth = ""
}
return pth, uiOpts, []SpecOption{WithSpecDocument(doc)}
} }
// RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec // RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec
@ -633,3 +716,7 @@ func (c *Context) RoutesHandler(builder Builder) http.Handler {
} }
return NewRouter(c, b(NewOperationExecutor(c))) return NewRouter(c, b(NewOperationExecutor(c)))
} }
func cantFindProducer(format string) string {
return "can't find a producer for " + format
}

View file

@ -2,6 +2,7 @@
package denco package denco
import ( import (
"errors"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
@ -29,13 +30,13 @@
// Router represents a URL router. // Router represents a URL router.
type Router struct { type Router struct {
param *doubleArray
// SizeHint expects the maximum number of path parameters in records to Build. // SizeHint expects the maximum number of path parameters in records to Build.
// SizeHint will be used to determine the capacity of the memory to allocate. // SizeHint will be used to determine the capacity of the memory to allocate.
// By default, SizeHint will be determined from given records to Build. // By default, SizeHint will be determined from given records to Build.
SizeHint int SizeHint int
static map[string]interface{} static map[string]interface{}
param *doubleArray
} }
// New returns a new Router. // New returns a new Router.
@ -51,7 +52,7 @@ func New() *Router {
// params is a slice of the Param that arranged in the order in which parameters appeared. // params is a slice of the Param that arranged in the order in which parameters appeared.
// e.g. when built routing path is "/path/to/:id/:name" and given path is "/path/to/1/alice". params order is [{"id": "1"}, {"name": "alice"}], not [{"name": "alice"}, {"id": "1"}]. // e.g. when built routing path is "/path/to/:id/:name" and given path is "/path/to/1/alice". params order is [{"id": "1"}, {"name": "alice"}], not [{"name": "alice"}, {"id": "1"}].
func (rt *Router) Lookup(path string) (data interface{}, params Params, found bool) { func (rt *Router) Lookup(path string) (data interface{}, params Params, found bool) {
if data, found := rt.static[path]; found { if data, found = rt.static[path]; found {
return data, nil, true return data, nil, true
} }
if len(rt.param.node) == 1 { if len(rt.param.node) == 1 {
@ -71,7 +72,7 @@ func (rt *Router) Lookup(path string) (data interface{}, params Params, found bo
func (rt *Router) Build(records []Record) error { func (rt *Router) Build(records []Record) error {
statics, params := makeRecords(records) statics, params := makeRecords(records)
if len(params) > MaxSize { if len(params) > MaxSize {
return fmt.Errorf("denco: too many records") return errors.New("denco: too many records")
} }
if rt.SizeHint < 0 { if rt.SizeHint < 0 {
rt.SizeHint = 0 rt.SizeHint = 0
@ -132,6 +133,7 @@ func newDoubleArray() *doubleArray {
// From the top, 22bits of BASE, 2bits of Extra flags and 8bits of CHECK. // From the top, 22bits of BASE, 2bits of Extra flags and 8bits of CHECK.
// //
// BASE (22bit) | Extra flags (2bit) | CHECK (8bit) // BASE (22bit) | Extra flags (2bit) | CHECK (8bit)
//
// |----------------------|--|--------| // |----------------------|--|--------|
// 32 10 8 0 // 32 10 8 0
type baseCheck uint32 type baseCheck uint32
@ -196,24 +198,29 @@ func (da *doubleArray) lookup(path string, params []Param, idx int) (*node, []Pa
if next := nextIndex(da.bc[idx].Base(), TerminationCharacter); next < len(da.bc) && da.bc[next].Check() == TerminationCharacter { if next := nextIndex(da.bc[idx].Base(), TerminationCharacter); next < len(da.bc) && da.bc[next].Check() == TerminationCharacter {
return da.node[da.bc[next].Base()], params, true return da.node[da.bc[next].Base()], params, true
} }
BACKTRACKING: BACKTRACKING:
for j := len(indices) - 1; j >= 0; j-- { for j := len(indices) - 1; j >= 0; j-- {
i, idx := int(indices[j]>>32), int(indices[j]&0xffffffff) i, idx := int(indices[j]>>32), int(indices[j]&0xffffffff)
if da.bc[idx].IsSingleParam() { if da.bc[idx].IsSingleParam() {
idx := nextIndex(da.bc[idx].Base(), ParamCharacter) nextIdx := nextIndex(da.bc[idx].Base(), ParamCharacter)
if idx >= len(da.bc) { if nextIdx >= len(da.bc) {
break break
} }
next := NextSeparator(path, i) next := NextSeparator(path, i)
params := append(params, Param{Value: path[i:next]}) nextParams := params
if nd, params, found := da.lookup(path[next:], params, idx); found { nextParams = append(nextParams, Param{Value: path[i:next]})
return nd, params, true if nd, nextNextParams, found := da.lookup(path[next:], nextParams, nextIdx); found {
return nd, nextNextParams, true
} }
} }
if da.bc[idx].IsWildcardParam() { if da.bc[idx].IsWildcardParam() {
idx := nextIndex(da.bc[idx].Base(), WildcardCharacter) nextIdx := nextIndex(da.bc[idx].Base(), WildcardCharacter)
params := append(params, Param{Value: path[i:]}) nextParams := params
return da.node[da.bc[idx].Base()], params, true nextParams = append(nextParams, Param{Value: path[i:]})
return da.node[da.bc[nextIdx].Base()], nextParams, true
} }
} }
return nil, nil, false return nil, nil, false
@ -325,7 +332,7 @@ func (da *doubleArray) arrange(records []*record, idx, depth int, usedBase map[i
} }
base = da.findBase(siblings, idx, usedBase) base = da.findBase(siblings, idx, usedBase)
if base > MaxSize { if base > MaxSize {
return -1, nil, nil, fmt.Errorf("denco: too many elements of internal slice") return -1, nil, nil, errors.New("denco: too many elements of internal slice")
} }
da.setBase(idx, base) da.setBase(idx, base)
return base, siblings, leaf, err return base, siblings, leaf, err
@ -386,7 +393,7 @@ func makeSiblings(records []*record, depth int) (sib []sibling, leaf *record, er
case pc == c: case pc == c:
continue continue
default: default:
return nil, nil, fmt.Errorf("denco: BUG: routing table hasn't been sorted") return nil, nil, errors.New("denco: BUG: routing table hasn't been sorted")
} }
if n > 0 { if n > 0 {
sib[n-1].end = i sib[n-1].end = i
@ -431,7 +438,7 @@ func makeRecords(srcs []Record) (statics, params []*record) {
wildcardPrefix := string(SeparatorCharacter) + string(WildcardCharacter) wildcardPrefix := string(SeparatorCharacter) + string(WildcardCharacter)
restconfPrefix := string(PathParamCharacter) + string(ParamCharacter) restconfPrefix := string(PathParamCharacter) + string(ParamCharacter)
for _, r := range srcs { for _, r := range srcs {
if strings.Contains(r.Key, paramPrefix) || strings.Contains(r.Key, wildcardPrefix) ||strings.Contains(r.Key, restconfPrefix){ if strings.Contains(r.Key, paramPrefix) || strings.Contains(r.Key, wildcardPrefix) || strings.Contains(r.Key, restconfPrefix) {
r.Key += termChar r.Key += termChar
params = append(params, &record{Record: r}) params = append(params, &record{Record: r})
} else { } else {

View file

@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
/*Package middleware provides the library with helper functions for serving swagger APIs. /*
Package middleware provides the library with helper functions for serving swagger APIs.
Pseudo middleware handler Pseudo middleware handler

View file

@ -1,9 +0,0 @@
// +build go1.8
package middleware
import "net/url"
func pathUnescape(path string) (string, error) {
return url.PathUnescape(path)
}

View file

@ -195,7 +195,8 @@ func ParseAccept2(header http.Header, key string) (specs []AcceptSpec) {
} }
// ParseAccept parses Accept* headers. // ParseAccept parses Accept* headers.
func ParseAccept(header http.Header, key string) (specs []AcceptSpec) { func ParseAccept(header http.Header, key string) []AcceptSpec {
var specs []AcceptSpec
loop: loop:
for _, s := range header[key] { for _, s := range header[key] {
for { for {
@ -218,6 +219,7 @@ func ParseAccept(header http.Header, key string) (specs []AcceptSpec) {
} }
} }
} }
specs = append(specs, spec) specs = append(specs, spec)
s = skipSpace(s) s = skipSpace(s)
if !strings.HasPrefix(s, ",") { if !strings.HasPrefix(s, ",") {
@ -226,7 +228,8 @@ func ParseAccept(header http.Header, key string) (specs []AcceptSpec) {
s = skipSpace(s[1:]) s = skipSpace(s[1:])
} }
} }
return
return specs
} }
func skipSpace(s string) (rest string) { func skipSpace(s string) (rest string) {
@ -306,7 +309,7 @@ func expectTokenOrQuoted(s string) (value string, rest string) {
p := make([]byte, len(s)-1) p := make([]byte, len(s)-1)
j := copy(p, s[:i]) j := copy(p, s[:i])
escape := true escape := true
for i = i + 1; i < len(s); i++ { for i++; i < len(s); i++ {
b := s[i] b := s[i]
switch { switch {
case escape: case escape:

View file

@ -34,6 +34,11 @@
const defaultMaxMemory = 32 << 20 const defaultMaxMemory = 32 << 20
const (
typeString = "string"
typeArray = "array"
)
var textUnmarshalType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() var textUnmarshalType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
func newUntypedParamBinder(param spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *untypedParamBinder { func newUntypedParamBinder(param spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *untypedParamBinder {
@ -66,7 +71,7 @@ func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items
case "boolean": case "boolean":
return reflect.TypeOf(true) return reflect.TypeOf(true)
case "string": case typeString:
if tt, ok := p.formats.GetType(format); ok { if tt, ok := p.formats.GetType(format); ok {
return tt return tt
} }
@ -94,7 +99,7 @@ func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items
return reflect.TypeOf(float64(0)) return reflect.TypeOf(float64(0))
} }
case "array": case typeArray:
if items == nil { if items == nil {
return nil return nil
} }
@ -119,7 +124,7 @@ func (p *untypedParamBinder) allowsMulti() bool {
func (p *untypedParamBinder) readValue(values runtime.Gettable, target reflect.Value) ([]string, bool, bool, error) { func (p *untypedParamBinder) readValue(values runtime.Gettable, target reflect.Value) ([]string, bool, bool, error) {
name, in, cf, tpe := p.parameter.Name, p.parameter.In, p.parameter.CollectionFormat, p.parameter.Type name, in, cf, tpe := p.parameter.Name, p.parameter.In, p.parameter.CollectionFormat, p.parameter.Type
if tpe == "array" { if tpe == typeArray {
if cf == "multi" { if cf == "multi" {
if !p.allowsMulti() { if !p.allowsMulti() {
return nil, false, false, errors.InvalidCollectionFormat(name, in, cf) return nil, false, false, errors.InvalidCollectionFormat(name, in, cf)
@ -208,10 +213,11 @@ func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams
if ffErr != nil { if ffErr != nil {
if p.parameter.Required { if p.parameter.Required {
return errors.NewParseError(p.Name, p.parameter.In, "", ffErr) return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
} else { }
return nil return nil
} }
}
target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header})) target.Set(reflect.ValueOf(runtime.File{Data: file, Header: header}))
return nil return nil
} }
@ -263,7 +269,7 @@ func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams
} }
func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflect.Value) error { func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflect.Value) error {
if p.parameter.Type == "array" { if p.parameter.Type == typeArray {
return p.setSliceFieldValue(target, p.parameter.Default, data, hasKey) return p.setSliceFieldValue(target, p.parameter.Default, data, hasKey)
} }
var d string var d string
@ -273,7 +279,7 @@ func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflec
return p.setFieldValue(target, p.parameter.Default, d, hasKey) return p.setFieldValue(target, p.parameter.Default, d, hasKey)
} }
func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue interface{}, data string, hasKey bool) error { func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue interface{}, data string, hasKey bool) error { //nolint:gocyclo
tpe := p.parameter.Type tpe := p.parameter.Type
if p.parameter.Format != "" { if p.parameter.Format != "" {
tpe = p.parameter.Format tpe = p.parameter.Format
@ -317,7 +323,7 @@ func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue in
return nil return nil
} }
switch target.Kind() { switch target.Kind() { //nolint:exhaustive // we want to check only types that map from a swagger parameter
case reflect.Bool: case reflect.Bool:
if data == "" { if data == "" {
if target.CanSet() { if target.CanSet() {

View file

@ -1,9 +0,0 @@
// +build !go1.8
package middleware
import "net/url"
func pathUnescape(path string) (string, error) {
return url.QueryUnescape(path)
}

View file

@ -10,67 +10,57 @@
// RapiDocOpts configures the RapiDoc middlewares // RapiDocOpts configures the RapiDoc middlewares
type RapiDocOpts struct { type RapiDocOpts struct {
// BasePath for the UI path, defaults to: / // BasePath for the UI, defaults to: /
BasePath string BasePath string
// Path combines with BasePath for the full UI path, defaults to: docs
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
Path string Path string
// SpecURL the url to find the spec for
// SpecURL is the URL of the spec document.
//
// Defaults to: /swagger.json
SpecURL string SpecURL string
// RapiDocURL for the js that generates the rapidoc site, defaults to: https://cdn.jsdelivr.net/npm/rapidoc/bundles/rapidoc.standalone.js
RapiDocURL string
// Title for the documentation site, default to: API documentation // Title for the documentation site, default to: API documentation
Title string Title string
// Template specifies a custom template to serve the UI
Template string
// RapiDocURL points to the js asset that generates the rapidoc site.
//
// Defaults to https://unpkg.com/rapidoc/dist/rapidoc-min.js
RapiDocURL string
} }
// EnsureDefaults in case some options are missing
func (r *RapiDocOpts) EnsureDefaults() { func (r *RapiDocOpts) EnsureDefaults() {
if r.BasePath == "" { common := toCommonUIOptions(r)
r.BasePath = "/" common.EnsureDefaults()
} fromCommonToAnyOptions(common, r)
if r.Path == "" {
r.Path = "docs" // rapidoc-specifics
}
if r.SpecURL == "" {
r.SpecURL = "/swagger.json"
}
if r.RapiDocURL == "" { if r.RapiDocURL == "" {
r.RapiDocURL = rapidocLatest r.RapiDocURL = rapidocLatest
} }
if r.Title == "" { if r.Template == "" {
r.Title = "API documentation" r.Template = rapidocTemplate
} }
} }
// RapiDoc creates a middleware to serve a documentation site for a swagger spec. // RapiDoc creates a middleware to serve a documentation site for a swagger spec.
// This allows for altering the spec before starting the http listener.
// //
// This allows for altering the spec before starting the http listener.
func RapiDoc(opts RapiDocOpts, next http.Handler) http.Handler { func RapiDoc(opts RapiDocOpts, next http.Handler) http.Handler {
opts.EnsureDefaults() opts.EnsureDefaults()
pth := path.Join(opts.BasePath, opts.Path) pth := path.Join(opts.BasePath, opts.Path)
tmpl := template.Must(template.New("rapidoc").Parse(rapidocTemplate)) tmpl := template.Must(template.New("rapidoc").Parse(opts.Template))
assets := bytes.NewBuffer(nil)
buf := bytes.NewBuffer(nil) if err := tmpl.Execute(assets, opts); err != nil {
_ = tmpl.Execute(buf, opts) panic(fmt.Errorf("cannot execute template: %w", err))
b := buf.Bytes()
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if r.URL.Path == pth {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write(b)
return
} }
if next == nil { return serveUI(pth, assets.Bytes(), next)
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
return
}
next.ServeHTTP(rw, r)
})
} }
const ( const (
@ -79,7 +69,7 @@ func RapiDoc(opts RapiDocOpts, next http.Handler) http.Handler {
<html> <html>
<head> <head>
<title>{{ .Title }}</title> <title>{{ .Title }}</title>
<meta charset="utf-8"> <!-- Important: rapi-doc uses utf8 charecters --> <meta charset="utf-8"> <!-- Important: rapi-doc uses utf8 characters -->
<script type="module" src="{{ .RapiDocURL }}"></script> <script type="module" src="{{ .RapiDocURL }}"></script>
</head> </head>
<body> <body>

View file

@ -10,67 +10,58 @@
// RedocOpts configures the Redoc middlewares // RedocOpts configures the Redoc middlewares
type RedocOpts struct { type RedocOpts struct {
// BasePath for the UI path, defaults to: / // BasePath for the UI, defaults to: /
BasePath string BasePath string
// Path combines with BasePath for the full UI path, defaults to: docs
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
Path string Path string
// SpecURL the url to find the spec for
// SpecURL is the URL of the spec document.
//
// Defaults to: /swagger.json
SpecURL string SpecURL string
// RedocURL for the js that generates the redoc site, defaults to: https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js
RedocURL string
// Title for the documentation site, default to: API documentation // Title for the documentation site, default to: API documentation
Title string Title string
// Template specifies a custom template to serve the UI
Template string
// RedocURL points to the js that generates the redoc site.
//
// Defaults to: https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js
RedocURL string
} }
// EnsureDefaults in case some options are missing // EnsureDefaults in case some options are missing
func (r *RedocOpts) EnsureDefaults() { func (r *RedocOpts) EnsureDefaults() {
if r.BasePath == "" { common := toCommonUIOptions(r)
r.BasePath = "/" common.EnsureDefaults()
} fromCommonToAnyOptions(common, r)
if r.Path == "" {
r.Path = "docs" // redoc-specifics
}
if r.SpecURL == "" {
r.SpecURL = "/swagger.json"
}
if r.RedocURL == "" { if r.RedocURL == "" {
r.RedocURL = redocLatest r.RedocURL = redocLatest
} }
if r.Title == "" { if r.Template == "" {
r.Title = "API documentation" r.Template = redocTemplate
} }
} }
// Redoc creates a middleware to serve a documentation site for a swagger spec. // Redoc creates a middleware to serve a documentation site for a swagger spec.
// This allows for altering the spec before starting the http listener.
// //
// This allows for altering the spec before starting the http listener.
func Redoc(opts RedocOpts, next http.Handler) http.Handler { func Redoc(opts RedocOpts, next http.Handler) http.Handler {
opts.EnsureDefaults() opts.EnsureDefaults()
pth := path.Join(opts.BasePath, opts.Path) pth := path.Join(opts.BasePath, opts.Path)
tmpl := template.Must(template.New("redoc").Parse(redocTemplate)) tmpl := template.Must(template.New("redoc").Parse(opts.Template))
assets := bytes.NewBuffer(nil)
buf := bytes.NewBuffer(nil) if err := tmpl.Execute(assets, opts); err != nil {
_ = tmpl.Execute(buf, opts) panic(fmt.Errorf("cannot execute template: %w", err))
b := buf.Bytes()
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if r.URL.Path == pth {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write(b)
return
} }
if next == nil { return serveUI(pth, assets.Bytes(), next)
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
return
}
next.ServeHTTP(rw, r)
})
} }
const ( const (

View file

@ -19,10 +19,10 @@
"reflect" "reflect"
"github.com/go-openapi/errors" "github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/spec" "github.com/go-openapi/spec"
"github.com/go-openapi/strfmt" "github.com/go-openapi/strfmt"
"github.com/go-openapi/runtime"
) )
// UntypedRequestBinder binds and validates the data from a http request // UntypedRequestBinder binds and validates the data from a http request
@ -31,6 +31,7 @@ type UntypedRequestBinder struct {
Parameters map[string]spec.Parameter Parameters map[string]spec.Parameter
Formats strfmt.Registry Formats strfmt.Registry
paramBinders map[string]*untypedParamBinder paramBinders map[string]*untypedParamBinder
debugLogf func(string, ...any) // a logging function to debug context and all components using it
} }
// NewUntypedRequestBinder creates a new binder for reading a request. // NewUntypedRequestBinder creates a new binder for reading a request.
@ -44,6 +45,7 @@ func NewUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Sw
paramBinders: binders, paramBinders: binders,
Spec: spec, Spec: spec,
Formats: formats, Formats: formats,
debugLogf: debugLogfFunc(nil),
} }
} }
@ -52,10 +54,10 @@ func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RoutePara
val := reflect.Indirect(reflect.ValueOf(data)) val := reflect.Indirect(reflect.ValueOf(data))
isMap := val.Kind() == reflect.Map isMap := val.Kind() == reflect.Map
var result []error var result []error
debugLog("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath()) o.debugLogf("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath())
for fieldName, param := range o.Parameters { for fieldName, param := range o.Parameters {
binder := o.paramBinders[fieldName] binder := o.paramBinders[fieldName]
debugLog("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath()) o.debugLogf("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath())
var target reflect.Value var target reflect.Value
if !isMap { if !isMap {
binder.Name = fieldName binder.Name = fieldName
@ -65,7 +67,7 @@ func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RoutePara
if isMap { if isMap {
tpe := binder.Type() tpe := binder.Type()
if tpe == nil { if tpe == nil {
if param.Schema.Type.Contains("array") { if param.Schema.Type.Contains(typeArray) {
tpe = reflect.TypeOf([]interface{}{}) tpe = reflect.TypeOf([]interface{}{})
} else { } else {
tpe = reflect.TypeOf(map[string]interface{}{}) tpe = reflect.TypeOf(map[string]interface{}{})
@ -102,3 +104,14 @@ func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RoutePara
return nil return nil
} }
// SetLogger allows for injecting a logger to catch debug entries.
//
// The logger is enabled in DEBUG mode only.
func (o *UntypedRequestBinder) SetLogger(lg logger.Logger) {
o.debugLogf = debugLogfFunc(lg)
}
func (o *UntypedRequestBinder) setDebugLogf(fn func(string, ...any)) {
o.debugLogf = fn
}

View file

@ -17,10 +17,12 @@
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"net/url"
fpath "path" fpath "path"
"regexp" "regexp"
"strings" "strings"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/security" "github.com/go-openapi/runtime/security"
"github.com/go-openapi/swag" "github.com/go-openapi/swag"
@ -67,10 +69,10 @@ func (r RouteParams) GetOK(name string) ([]string, bool, bool) {
return nil, false, false return nil, false, false
} }
// NewRouter creates a new context aware router middleware // NewRouter creates a new context-aware router middleware
func NewRouter(ctx *Context, next http.Handler) http.Handler { func NewRouter(ctx *Context, next http.Handler) http.Handler {
if ctx.router == nil { if ctx.router == nil {
ctx.router = DefaultRouter(ctx.spec, ctx.api) ctx.router = DefaultRouter(ctx.spec, ctx.api, WithDefaultRouterLoggerFunc(ctx.debugLogf))
} }
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
@ -103,7 +105,7 @@ type RoutableAPI interface {
DefaultConsumes() string DefaultConsumes() string
} }
// Router represents a swagger aware router // Router represents a swagger-aware router
type Router interface { type Router interface {
Lookup(method, path string) (*MatchedRoute, bool) Lookup(method, path string) (*MatchedRoute, bool)
OtherMethods(method, path string) []string OtherMethods(method, path string) []string
@ -114,30 +116,64 @@ type defaultRouteBuilder struct {
analyzer *analysis.Spec analyzer *analysis.Spec
api RoutableAPI api RoutableAPI
records map[string][]denco.Record records map[string][]denco.Record
debugLogf func(string, ...any) // a logging function to debug context and all components using it
} }
type defaultRouter struct { type defaultRouter struct {
spec *loads.Document spec *loads.Document
routers map[string]*denco.Router routers map[string]*denco.Router
debugLogf func(string, ...any) // a logging function to debug context and all components using it
} }
func newDefaultRouteBuilder(spec *loads.Document, api RoutableAPI) *defaultRouteBuilder { func newDefaultRouteBuilder(spec *loads.Document, api RoutableAPI, opts ...DefaultRouterOpt) *defaultRouteBuilder {
var o defaultRouterOpts
for _, apply := range opts {
apply(&o)
}
if o.debugLogf == nil {
o.debugLogf = debugLogfFunc(nil) // defaults to standard logger
}
return &defaultRouteBuilder{ return &defaultRouteBuilder{
spec: spec, spec: spec,
analyzer: analysis.New(spec.Spec()), analyzer: analysis.New(spec.Spec()),
api: api, api: api,
records: make(map[string][]denco.Record), records: make(map[string][]denco.Record),
debugLogf: o.debugLogf,
} }
} }
// DefaultRouter creates a default implemenation of the router // DefaultRouterOpt allows to inject optional behavior to the default router.
func DefaultRouter(spec *loads.Document, api RoutableAPI) Router { type DefaultRouterOpt func(*defaultRouterOpts)
builder := newDefaultRouteBuilder(spec, api)
type defaultRouterOpts struct {
debugLogf func(string, ...any)
}
// WithDefaultRouterLogger sets the debug logger for the default router.
//
// This is enabled only in DEBUG mode.
func WithDefaultRouterLogger(lg logger.Logger) DefaultRouterOpt {
return func(o *defaultRouterOpts) {
o.debugLogf = debugLogfFunc(lg)
}
}
// WithDefaultRouterLoggerFunc sets a logging debug method for the default router.
func WithDefaultRouterLoggerFunc(fn func(string, ...any)) DefaultRouterOpt {
return func(o *defaultRouterOpts) {
o.debugLogf = fn
}
}
// DefaultRouter creates a default implementation of the router
func DefaultRouter(spec *loads.Document, api RoutableAPI, opts ...DefaultRouterOpt) Router {
builder := newDefaultRouteBuilder(spec, api, opts...)
if spec != nil { if spec != nil {
for method, paths := range builder.analyzer.Operations() { for method, paths := range builder.analyzer.Operations() {
for path, operation := range paths { for path, operation := range paths {
fp := fpath.Join(spec.BasePath(), path) fp := fpath.Join(spec.BasePath(), path)
debugLog("adding route %s %s %q", method, fp, operation.ID) builder.debugLogf("adding route %s %s %q", method, fp, operation.ID)
builder.AddRoute(method, fp, operation) builder.AddRoute(method, fp, operation)
} }
} }
@ -319,24 +355,24 @@ func (m *MatchedRoute) NeedsAuth() bool {
func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) { func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
mth := strings.ToUpper(method) mth := strings.ToUpper(method)
debugLog("looking up route for %s %s", method, path) d.debugLogf("looking up route for %s %s", method, path)
if Debug { if Debug {
if len(d.routers) == 0 { if len(d.routers) == 0 {
debugLog("there are no known routers") d.debugLogf("there are no known routers")
} }
for meth := range d.routers { for meth := range d.routers {
debugLog("got a router for %s", meth) d.debugLogf("got a router for %s", meth)
} }
} }
if router, ok := d.routers[mth]; ok { if router, ok := d.routers[mth]; ok {
if m, rp, ok := router.Lookup(fpath.Clean(path)); ok && m != nil { if m, rp, ok := router.Lookup(fpath.Clean(path)); ok && m != nil {
if entry, ok := m.(*routeEntry); ok { if entry, ok := m.(*routeEntry); ok {
debugLog("found a route for %s %s with %d parameters", method, path, len(entry.Parameters)) d.debugLogf("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
var params RouteParams var params RouteParams
for _, p := range rp { for _, p := range rp {
v, err := pathUnescape(p.Value) v, err := url.PathUnescape(p.Value)
if err != nil { if err != nil {
debugLog("failed to escape %q: %v", p.Value, err) d.debugLogf("failed to escape %q: %v", p.Value, err)
v = p.Value v = p.Value
} }
// a workaround to handle fragment/composing parameters until they are supported in denco router // a workaround to handle fragment/composing parameters until they are supported in denco router
@ -356,10 +392,10 @@ func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
return &MatchedRoute{routeEntry: *entry, Params: params}, true return &MatchedRoute{routeEntry: *entry, Params: params}, true
} }
} else { } else {
debugLog("couldn't find a route by path for %s %s", method, path) d.debugLogf("couldn't find a route by path for %s %s", method, path)
} }
} else { } else {
debugLog("couldn't find a route by method for %s %s", method, path) d.debugLogf("couldn't find a route by method for %s %s", method, path)
} }
return nil, false return nil, false
} }
@ -378,6 +414,10 @@ func (d *defaultRouter) OtherMethods(method, path string) []string {
return methods return methods
} }
func (d *defaultRouter) SetLogger(lg logger.Logger) {
d.debugLogf = debugLogfFunc(lg)
}
// convert swagger parameters per path segment into a denco parameter as multiple parameters per segment are not supported in denco // convert swagger parameters per path segment into a denco parameter as multiple parameters per segment are not supported in denco
var pathConverter = regexp.MustCompile(`{(.+?)}([^/]*)`) var pathConverter = regexp.MustCompile(`{(.+?)}([^/]*)`)
@ -413,7 +453,7 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
bp = bp[:len(bp)-1] bp = bp[:len(bp)-1]
} }
debugLog("operation: %#v", *operation) d.debugLogf("operation: %#v", *operation)
if handler, ok := d.api.HandlerFor(method, strings.TrimPrefix(path, bp)); ok { if handler, ok := d.api.HandlerFor(method, strings.TrimPrefix(path, bp)); ok {
consumes := d.analyzer.ConsumesFor(operation) consumes := d.analyzer.ConsumesFor(operation)
produces := d.analyzer.ProducesFor(operation) produces := d.analyzer.ProducesFor(operation)
@ -428,6 +468,8 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
produces = append(produces, defProduces) produces = append(produces, defProduces)
} }
requestBinder := NewUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats())
requestBinder.setDebugLogf(d.debugLogf)
record := denco.NewRecord(pathConverter.ReplaceAllString(path, ":$1"), &routeEntry{ record := denco.NewRecord(pathConverter.ReplaceAllString(path, ":$1"), &routeEntry{
BasePath: bp, BasePath: bp,
PathPattern: path, PathPattern: path,
@ -439,7 +481,7 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
Producers: d.api.ProducersFor(normalizeOffers(produces)), Producers: d.api.ProducersFor(normalizeOffers(produces)),
Parameters: parameters, Parameters: parameters,
Formats: d.api.Formats(), Formats: d.api.Formats(),
Binder: NewUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats()), Binder: requestBinder,
Authenticators: d.buildAuthenticators(operation), Authenticators: d.buildAuthenticators(operation),
Authorizer: d.api.Authorizer(), Authorizer: d.api.Authorizer(),
}) })
@ -449,11 +491,11 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
func (d *defaultRouteBuilder) buildAuthenticators(operation *spec.Operation) RouteAuthenticators { func (d *defaultRouteBuilder) buildAuthenticators(operation *spec.Operation) RouteAuthenticators {
requirements := d.analyzer.SecurityRequirementsFor(operation) requirements := d.analyzer.SecurityRequirementsFor(operation)
var auths []RouteAuthenticator auths := make([]RouteAuthenticator, 0, len(requirements))
for _, reqs := range requirements { for _, reqs := range requirements {
var schemes []string schemes := make([]string, 0, len(reqs))
scopes := make(map[string][]string, len(reqs)) scopes := make(map[string][]string, len(reqs))
var scopeSlices [][]string scopeSlices := make([][]string, 0, len(reqs))
for _, req := range reqs { for _, req := range reqs {
schemes = append(schemes, req.Name) schemes = append(schemes, req.Name)
scopes[req.Name] = req.Scopes scopes[req.Name] = req.Scopes
@ -484,5 +526,6 @@ func (d *defaultRouteBuilder) Build() *defaultRouter {
return &defaultRouter{ return &defaultRouter{
spec: d.spec, spec: d.spec,
routers: routers, routers: routers,
debugLogf: d.debugLogf,
} }
} }

View file

@ -19,30 +19,84 @@
"path" "path"
) )
// Spec creates a middleware to serve a swagger spec. const (
// This allows for altering the spec before starting the http listener. contentTypeHeader = "Content-Type"
// This can be useful if you want to serve the swagger spec from another path than /swagger.json applicationJSON = "application/json"
)
// SpecOption can be applied to the Spec serving middleware
type SpecOption func(*specOptions)
var defaultSpecOptions = specOptions{
Path: "",
Document: "swagger.json",
}
type specOptions struct {
Path string
Document string
}
func specOptionsWithDefaults(opts []SpecOption) specOptions {
o := defaultSpecOptions
for _, apply := range opts {
apply(&o)
}
return o
}
// Spec creates a middleware to serve a swagger spec as a JSON document.
// //
func Spec(basePath string, b []byte, next http.Handler) http.Handler { // This allows for altering the spec before starting the http listener.
//
// The basePath argument indicates the path of the spec document (defaults to "/").
// Additional SpecOption can be used to change the name of the document (defaults to "swagger.json").
func Spec(basePath string, b []byte, next http.Handler, opts ...SpecOption) http.Handler {
if basePath == "" { if basePath == "" {
basePath = "/" basePath = "/"
} }
pth := path.Join(basePath, "swagger.json") o := specOptionsWithDefaults(opts)
pth := path.Join(basePath, o.Path, o.Document)
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if r.URL.Path == pth { if path.Clean(r.URL.Path) == pth {
rw.Header().Set("Content-Type", "application/json") rw.Header().Set(contentTypeHeader, applicationJSON)
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
//#nosec
_, _ = rw.Write(b) _, _ = rw.Write(b)
return return
} }
if next == nil { if next != nil {
rw.Header().Set("Content-Type", "application/json") next.ServeHTTP(rw, r)
rw.WriteHeader(http.StatusNotFound)
return return
} }
next.ServeHTTP(rw, r)
rw.Header().Set(contentTypeHeader, applicationJSON)
rw.WriteHeader(http.StatusNotFound)
}) })
} }
// WithSpecPath sets the path to be joined to the base path of the Spec middleware.
//
// This is empty by default.
func WithSpecPath(pth string) SpecOption {
return func(o *specOptions) {
o.Path = pth
}
}
// WithSpecDocument sets the name of the JSON document served as a spec.
//
// By default, this is "swagger.json"
func WithSpecDocument(doc string) SpecOption {
return func(o *specOptions) {
if doc == "" {
return
}
o.Document = doc
}
}

View file

@ -8,40 +8,65 @@
"path" "path"
) )
// SwaggerUIOpts configures the Swaggerui middlewares // SwaggerUIOpts configures the SwaggerUI middleware
type SwaggerUIOpts struct { type SwaggerUIOpts struct {
// BasePath for the UI path, defaults to: / // BasePath for the API, defaults to: /
BasePath string BasePath string
// Path combines with BasePath for the full UI path, defaults to: docs
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
Path string Path string
// SpecURL the url to find the spec for
// SpecURL is the URL of the spec document.
//
// Defaults to: /swagger.json
SpecURL string SpecURL string
// Title for the documentation site, default to: API documentation
Title string
// Template specifies a custom template to serve the UI
Template string
// OAuthCallbackURL the url called after OAuth2 login // OAuthCallbackURL the url called after OAuth2 login
OAuthCallbackURL string OAuthCallbackURL string
// The three components needed to embed swagger-ui // The three components needed to embed swagger-ui
// SwaggerURL points to the js that generates the SwaggerUI site.
//
// Defaults to: https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js
SwaggerURL string SwaggerURL string
SwaggerPresetURL string SwaggerPresetURL string
SwaggerStylesURL string SwaggerStylesURL string
Favicon32 string Favicon32 string
Favicon16 string Favicon16 string
// Title for the documentation site, default to: API documentation
Title string
} }
// EnsureDefaults in case some options are missing // EnsureDefaults in case some options are missing
func (r *SwaggerUIOpts) EnsureDefaults() { func (r *SwaggerUIOpts) EnsureDefaults() {
if r.BasePath == "" { r.ensureDefaults()
r.BasePath = "/"
if r.Template == "" {
r.Template = swaggeruiTemplate
} }
if r.Path == "" { }
r.Path = "docs"
} func (r *SwaggerUIOpts) EnsureDefaultsOauth2() {
if r.SpecURL == "" { r.ensureDefaults()
r.SpecURL = "/swagger.json"
if r.Template == "" {
r.Template = swaggerOAuthTemplate
} }
}
func (r *SwaggerUIOpts) ensureDefaults() {
common := toCommonUIOptions(r)
common.EnsureDefaults()
fromCommonToAnyOptions(common, r)
// swaggerui-specifics
if r.OAuthCallbackURL == "" { if r.OAuthCallbackURL == "" {
r.OAuthCallbackURL = path.Join(r.BasePath, r.Path, "oauth2-callback") r.OAuthCallbackURL = path.Join(r.BasePath, r.Path, "oauth2-callback")
} }
@ -60,40 +85,22 @@ func (r *SwaggerUIOpts) EnsureDefaults() {
if r.Favicon32 == "" { if r.Favicon32 == "" {
r.Favicon32 = swaggerFavicon32Latest r.Favicon32 = swaggerFavicon32Latest
} }
if r.Title == "" {
r.Title = "API documentation"
}
} }
// SwaggerUI creates a middleware to serve a documentation site for a swagger spec. // SwaggerUI creates a middleware to serve a documentation site for a swagger spec.
//
// This allows for altering the spec before starting the http listener. // This allows for altering the spec before starting the http listener.
func SwaggerUI(opts SwaggerUIOpts, next http.Handler) http.Handler { func SwaggerUI(opts SwaggerUIOpts, next http.Handler) http.Handler {
opts.EnsureDefaults() opts.EnsureDefaults()
pth := path.Join(opts.BasePath, opts.Path) pth := path.Join(opts.BasePath, opts.Path)
tmpl := template.Must(template.New("swaggerui").Parse(swaggeruiTemplate)) tmpl := template.Must(template.New("swaggerui").Parse(opts.Template))
assets := bytes.NewBuffer(nil)
buf := bytes.NewBuffer(nil) if err := tmpl.Execute(assets, opts); err != nil {
_ = tmpl.Execute(buf, &opts) panic(fmt.Errorf("cannot execute template: %w", err))
b := buf.Bytes()
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path.Join(r.URL.Path) == pth {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write(b)
return
} }
if next == nil { return serveUI(pth, assets.Bytes(), next)
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
return
}
next.ServeHTTP(rw, r)
})
} }
const ( const (

View file

@ -4,37 +4,20 @@
"bytes" "bytes"
"fmt" "fmt"
"net/http" "net/http"
"path"
"text/template" "text/template"
) )
func SwaggerUIOAuth2Callback(opts SwaggerUIOpts, next http.Handler) http.Handler { func SwaggerUIOAuth2Callback(opts SwaggerUIOpts, next http.Handler) http.Handler {
opts.EnsureDefaults() opts.EnsureDefaultsOauth2()
pth := opts.OAuthCallbackURL pth := opts.OAuthCallbackURL
tmpl := template.Must(template.New("swaggeroauth").Parse(swaggerOAuthTemplate)) tmpl := template.Must(template.New("swaggeroauth").Parse(opts.Template))
assets := bytes.NewBuffer(nil)
buf := bytes.NewBuffer(nil) if err := tmpl.Execute(assets, opts); err != nil {
_ = tmpl.Execute(buf, &opts) panic(fmt.Errorf("cannot execute template: %w", err))
b := buf.Bytes()
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path.Join(r.URL.Path) == pth {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write(b)
return
} }
if next == nil { return serveUI(pth, assets.Bytes(), next)
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
return
}
next.ServeHTTP(rw, r)
})
} }
const ( const (

View file

@ -0,0 +1,173 @@
package middleware
import (
"bytes"
"encoding/gob"
"fmt"
"net/http"
"path"
"strings"
)
const (
// constants that are common to all UI-serving middlewares
defaultDocsPath = "docs"
defaultDocsURL = "/swagger.json"
defaultDocsTitle = "API Documentation"
)
// uiOptions defines common options for UI serving middlewares.
type uiOptions struct {
// BasePath for the UI, defaults to: /
BasePath string
// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
Path string
// SpecURL is the URL of the spec document.
//
// Defaults to: /swagger.json
SpecURL string
// Title for the documentation site, default to: API documentation
Title string
// Template specifies a custom template to serve the UI
Template string
}
// toCommonUIOptions converts any UI option type to retain the common options.
//
// This uses gob encoding/decoding to convert common fields from one struct to another.
func toCommonUIOptions(opts interface{}) uiOptions {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
dec := gob.NewDecoder(&buf)
var o uiOptions
err := enc.Encode(opts)
if err != nil {
panic(err)
}
err = dec.Decode(&o)
if err != nil {
panic(err)
}
return o
}
func fromCommonToAnyOptions[T any](source uiOptions, target *T) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
dec := gob.NewDecoder(&buf)
err := enc.Encode(source)
if err != nil {
panic(err)
}
err = dec.Decode(target)
if err != nil {
panic(err)
}
}
// UIOption can be applied to UI serving middleware, such as Context.APIHandler or
// Context.APIHandlerSwaggerUI to alter the defaut behavior.
type UIOption func(*uiOptions)
func uiOptionsWithDefaults(opts []UIOption) uiOptions {
var o uiOptions
for _, apply := range opts {
apply(&o)
}
return o
}
// WithUIBasePath sets the base path from where to serve the UI assets.
//
// By default, Context middleware sets this value to the API base path.
func WithUIBasePath(base string) UIOption {
return func(o *uiOptions) {
if !strings.HasPrefix(base, "/") {
base = "/" + base
}
o.BasePath = base
}
}
// WithUIPath sets the path from where to serve the UI assets (i.e. /{basepath}/{path}.
func WithUIPath(pth string) UIOption {
return func(o *uiOptions) {
o.Path = pth
}
}
// WithUISpecURL sets the path from where to serve swagger spec document.
//
// This may be specified as a full URL or a path.
//
// By default, this is "/swagger.json"
func WithUISpecURL(specURL string) UIOption {
return func(o *uiOptions) {
o.SpecURL = specURL
}
}
// WithUITitle sets the title of the UI.
//
// By default, Context middleware sets this value to the title found in the API spec.
func WithUITitle(title string) UIOption {
return func(o *uiOptions) {
o.Title = title
}
}
// WithTemplate allows to set a custom template for the UI.
//
// UI middleware will panic if the template does not parse or execute properly.
func WithTemplate(tpl string) UIOption {
return func(o *uiOptions) {
o.Template = tpl
}
}
// EnsureDefaults in case some options are missing
func (r *uiOptions) EnsureDefaults() {
if r.BasePath == "" {
r.BasePath = "/"
}
if r.Path == "" {
r.Path = defaultDocsPath
}
if r.SpecURL == "" {
r.SpecURL = defaultDocsURL
}
if r.Title == "" {
r.Title = defaultDocsTitle
}
}
// serveUI creates a middleware that serves a templated asset as text/html.
func serveUI(pth string, assets []byte, next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path.Clean(r.URL.Path) == pth {
rw.Header().Set(contentTypeHeader, "text/html; charset=utf-8")
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write(assets)
return
}
if next != nil {
next.ServeHTTP(rw, r)
return
}
rw.Header().Set(contentTypeHeader, "text/plain")
rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
})
}

View file

@ -197,30 +197,31 @@ func (d *API) Validate() error {
// validateWith validates the registrations in this API against the provided spec analyzer // validateWith validates the registrations in this API against the provided spec analyzer
func (d *API) validate() error { func (d *API) validate() error {
var consumes []string consumes := make([]string, 0, len(d.consumers))
for k := range d.consumers { for k := range d.consumers {
consumes = append(consumes, k) consumes = append(consumes, k)
} }
var produces []string produces := make([]string, 0, len(d.producers))
for k := range d.producers { for k := range d.producers {
produces = append(produces, k) produces = append(produces, k)
} }
var authenticators []string authenticators := make([]string, 0, len(d.authenticators))
for k := range d.authenticators { for k := range d.authenticators {
authenticators = append(authenticators, k) authenticators = append(authenticators, k)
} }
var operations []string operations := make([]string, 0, len(d.operations))
for m, v := range d.operations { for m, v := range d.operations {
for p := range v { for p := range v {
operations = append(operations, fmt.Sprintf("%s %s", strings.ToUpper(m), p)) operations = append(operations, fmt.Sprintf("%s %s", strings.ToUpper(m), p))
} }
} }
var definedAuths []string secDefinitions := d.spec.Spec().SecurityDefinitions
for k := range d.spec.Spec().SecurityDefinitions { definedAuths := make([]string, 0, len(secDefinitions))
for k := range secDefinitions {
definedAuths = append(definedAuths, k) definedAuths = append(definedAuths, k)
} }
@ -267,7 +268,7 @@ func (d *API) verify(name string, registrations []string, expectations []string)
delete(expected, k) delete(expected, k)
} }
var unregistered []string unregistered := make([]string, 0, len(expected))
for k := range expected { for k := range expected {
unregistered = append(unregistered, k) unregistered = append(unregistered, k)
} }

View file

@ -35,7 +35,6 @@ type validation struct {
// ContentType validates the content type of a request // ContentType validates the content type of a request
func validateContentType(allowed []string, actual string) error { func validateContentType(allowed []string, actual string) error {
debugLog("validating content type for %q against [%s]", actual, strings.Join(allowed, ", "))
if len(allowed) == 0 { if len(allowed) == 0 {
return nil return nil
} }
@ -57,13 +56,13 @@ func validateContentType(allowed []string, actual string) error {
} }
func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *validation { func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *validation {
debugLog("validating request %s %s", request.Method, request.URL.EscapedPath())
validate := &validation{ validate := &validation{
context: ctx, context: ctx,
request: request, request: request,
route: route, route: route,
bound: make(map[string]interface{}), bound: make(map[string]interface{}),
} }
validate.debugLogf("validating request %s %s", request.Method, request.URL.EscapedPath())
validate.contentType() validate.contentType()
if len(validate.result) == 0 { if len(validate.result) == 0 {
@ -76,8 +75,12 @@ func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *
return validate return validate
} }
func (v *validation) debugLogf(format string, args ...any) {
v.context.debugLogf(format, args...)
}
func (v *validation) parameters() { func (v *validation) parameters() {
debugLog("validating request parameters for %s %s", v.request.Method, v.request.URL.EscapedPath()) v.debugLogf("validating request parameters for %s %s", v.request.Method, v.request.URL.EscapedPath())
if result := v.route.Binder.Bind(v.request, v.route.Params, v.route.Consumer, v.bound); result != nil { if result := v.route.Binder.Bind(v.request, v.route.Params, v.route.Consumer, v.bound); result != nil {
if result.Error() == "validation failure list" { if result.Error() == "validation failure list" {
for _, e := range result.(*errors.Validation).Value.([]interface{}) { for _, e := range result.(*errors.Validation).Value.([]interface{}) {
@ -91,7 +94,7 @@ func (v *validation) parameters() {
func (v *validation) contentType() { func (v *validation) contentType() {
if len(v.result) == 0 && runtime.HasBody(v.request) { if len(v.result) == 0 && runtime.HasBody(v.request) {
debugLog("validating body content type for %s %s", v.request.Method, v.request.URL.EscapedPath()) v.debugLogf("validating body content type for %s %s", v.request.Method, v.request.URL.EscapedPath())
ct, _, req, err := v.context.ContentType(v.request) ct, _, req, err := v.context.ContentType(v.request)
if err != nil { if err != nil {
v.result = append(v.result, err) v.result = append(v.result, err)
@ -100,6 +103,7 @@ func (v *validation) contentType() {
} }
if len(v.result) == 0 { if len(v.result) == 0 {
v.debugLogf("validating content type for %q against [%s]", ct, strings.Join(v.route.Consumes, ", "))
if err := validateContentType(v.route.Consumes, ct); err != nil { if err := validateContentType(v.route.Consumes, ct); err != nil {
v.result = append(v.result, err) v.result = append(v.result, err)
} }

View file

@ -16,6 +16,8 @@
import ( import (
"bufio" "bufio"
"context"
"errors"
"io" "io"
"net/http" "net/http"
"strings" "strings"
@ -96,10 +98,16 @@ func (p *peekingReader) Read(d []byte) (int, error) {
if p == nil { if p == nil {
return 0, io.EOF return 0, io.EOF
} }
if p.underlying == nil {
return 0, io.ErrUnexpectedEOF
}
return p.underlying.Read(d) return p.underlying.Read(d)
} }
func (p *peekingReader) Close() error { func (p *peekingReader) Close() error {
if p.underlying == nil {
return errors.New("reader already closed")
}
p.underlying = nil p.underlying = nil
if p.orig != nil { if p.orig != nil {
return p.orig.Close() return p.orig.Close()
@ -107,9 +115,11 @@ func (p *peekingReader) Close() error {
return nil return nil
} }
// JSONRequest creates a new http request with json headers set // JSONRequest creates a new http request with json headers set.
//
// It uses context.Background.
func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) { func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequest(method, urlStr, body) req, err := http.NewRequestWithContext(context.Background(), method, urlStr, body)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -27,10 +27,11 @@
const ( const (
query = "query" query = "query"
header = "header" header = "header"
accessTokenParam = "access_token"
) )
// HttpAuthenticator is a function that authenticates a HTTP request // HttpAuthenticator is a function that authenticates a HTTP request
func HttpAuthenticator(handler func(*http.Request) (bool, interface{}, error)) runtime.Authenticator { func HttpAuthenticator(handler func(*http.Request) (bool, interface{}, error)) runtime.Authenticator { //nolint:revive,stylecheck
return runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) { return runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) {
if request, ok := params.(*http.Request); ok { if request, ok := params.(*http.Request); ok {
return handler(request) return handler(request)
@ -158,7 +159,7 @@ func APIKeyAuth(name, in string, authenticate TokenAuthentication) runtime.Authe
inl := strings.ToLower(in) inl := strings.ToLower(in)
if inl != query && inl != header { if inl != query && inl != header {
// panic because this is most likely a typo // panic because this is most likely a typo
panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\".")) panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\""))
} }
var getToken func(*http.Request) string var getToken func(*http.Request) string
@ -186,7 +187,7 @@ func APIKeyAuthCtx(name, in string, authenticate TokenAuthenticationCtx) runtime
inl := strings.ToLower(in) inl := strings.ToLower(in)
if inl != query && inl != header { if inl != query && inl != header {
// panic because this is most likely a typo // panic because this is most likely a typo
panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\".")) panic(errors.New(500, "api key auth: in value needs to be either \"query\" or \"header\""))
} }
var getToken func(*http.Request) string var getToken func(*http.Request) string
@ -226,12 +227,12 @@ func BearerAuth(name string, authenticate ScopedTokenAuthentication) runtime.Aut
} }
if token == "" { if token == "" {
qs := r.Request.URL.Query() qs := r.Request.URL.Query()
token = qs.Get("access_token") token = qs.Get(accessTokenParam)
} }
//#nosec //#nosec
ct, _, _ := runtime.ContentType(r.Request.Header) ct, _, _ := runtime.ContentType(r.Request.Header)
if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") { if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") {
token = r.Request.FormValue("access_token") token = r.Request.FormValue(accessTokenParam)
} }
if token == "" { if token == "" {
@ -256,12 +257,12 @@ func BearerAuthCtx(name string, authenticate ScopedTokenAuthenticationCtx) runti
} }
if token == "" { if token == "" {
qs := r.Request.URL.Query() qs := r.Request.URL.Query()
token = qs.Get("access_token") token = qs.Get(accessTokenParam)
} }
//#nosec //#nosec
ct, _, _ := runtime.ContentType(r.Request.Header) ct, _, _ := runtime.ContentType(r.Request.Header)
if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") { if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") {
token = r.Request.FormValue("access_token") token = r.Request.FormValue(accessTokenParam)
} }
if token == "" { if token == "" {

View file

@ -1,2 +1 @@
secrets.yml *.out
coverage.out

View file

@ -11,7 +11,7 @@ linters-settings:
threshold: 200 threshold: 200
goconst: goconst:
min-len: 2 min-len: 2
min-occurrences: 2 min-occurrences: 3
linters: linters:
enable-all: true enable-all: true
@ -40,3 +40,22 @@ linters:
- tparallel - tparallel
- thelper - thelper
- ifshort - ifshort
- exhaustruct
- varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase

View file

@ -1,8 +1,5 @@
# OAI object model # OpenAPI v2 object model [![Build Status](https://github.com/go-openapi/spec/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/spec/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec)
[![Build Status](https://travis-ci.org/go-openapi/spec.svg?branch=master)](https://travis-ci.org/go-openapi/spec)
<!-- [![Build status](https://ci.appveyor.com/api/projects/status/x377t5o9ennm847o/branch/master?svg=true)](https://ci.appveyor.com/project/casualjim/go-openapi/spec/branch/master) -->
[![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/spec.svg)](https://pkg.go.dev/github.com/go-openapi/spec) [![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/spec.svg)](https://pkg.go.dev/github.com/go-openapi/spec)
@ -32,3 +29,26 @@ The object model for OpenAPI specification documents.
> This [discussion thread](https://github.com/go-openapi/spec/issues/21) relates the full story. > This [discussion thread](https://github.com/go-openapi/spec/issues/21) relates the full story.
> >
> An early attempt to support Swagger 3 may be found at: https://github.com/go-openapi/spec3 > An early attempt to support Swagger 3 may be found at: https://github.com/go-openapi/spec3
* Does the unmarshaling support YAML?
> Not directly. The exposed types know only how to unmarshal from JSON.
>
> In order to load a YAML document as a Swagger spec, you need to use the loaders provided by
> github.com/go-openapi/loads
>
> Take a look at the example there: https://pkg.go.dev/github.com/go-openapi/loads#example-Spec
>
> See also https://github.com/go-openapi/spec/issues/164
* How can I validate a spec?
> Validation is provided by [the validate package](http://github.com/go-openapi/validate)
* Why do we have an `ID` field for `Schema` which is not part of the swagger spec?
> We found jsonschema compatibility more important: since `id` in jsonschema influences
> how `$ref` are resolved.
> This `id` does not conflict with any property named `id`.
>
> See also https://github.com/go-openapi/spec/issues/23

View file

@ -1,32 +0,0 @@
version: "0.1.{build}"
clone_folder: C:\go-openapi\spec
shallow_clone: true # for startup speed
pull_requests:
do_not_increment_build_number: true
#skip_tags: true
#skip_branch_with_pr: true
# appveyor.yml
build: off
environment:
GOPATH: c:\gopath
stack: go 1.15
test_script:
- go test -v -timeout 20m ./...
deploy: off
notifications:
- provider: Slack
incoming_webhook: https://hooks.slack.com/services/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
auth_token:
secure: Sf7kZf7ZGbnwWUMpffHwMu5A0cHkLK2MYY32LNTPj4+/3qC3Ghl7+9v4TSLOqOlCwdRNjOGblAq7s+GDJed6/xgRQl1JtCi1klzZNrYX4q01pgTPvvGcwbBkIYgeMaPeIRcK9OZnud7sRXdttozgTOpytps2U6Js32ip7uj5mHSg2ub0FwoSJwlS6dbezZ8+eDhoha0F/guY99BEwx8Bd+zROrT2TFGsSGOFGN6wFc7moCqTHO/YkWib13a2QNXqOxCCVBy/lt76Wp+JkeFppjHlzs/2lP3EAk13RIUAaesdEUHvIHrzCyNJEd3/+KO2DzsWOYfpktd+KBCvgaYOsoo7ubdT3IROeAegZdCgo/6xgCEsmFc9ZcqCfN5yNx2A+BZ2Vwmpws+bQ1E1+B5HDzzaiLcYfG4X2O210QVGVDLWsv1jqD+uPYeHY2WRfh5ZsIUFvaqgUEnwHwrK44/8REAhQavt1QAj5uJpsRd7CkRVPWRNK+yIky+wgbVUFEchRNmS55E7QWf+W4+4QZkQi7vUTMc9nbTUu2Es9NfvfudOpM2wZbn98fjpb/qq/nRv6Bk+ca+7XD5/IgNLMbWp2ouDdzbiHLCOfDUiHiDJhLfFZx9Bwo7ZwfzeOlbrQX66bx7xRKYmOe4DLrXhNcpbsMa8qbfxlZRCmYbubB/Y8h4=
channel: bots
on_build_success: false
on_build_failure: true
on_build_status_changed: true

File diff suppressed because one or more lines are too long

17
vendor/github.com/go-openapi/spec/embed.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
package spec
import (
"embed"
"path"
)
//go:embed schemas/*.json schemas/*/*.json
var assets embed.FS
func jsonschemaDraft04JSONBytes() ([]byte, error) {
return assets.ReadFile(path.Join("schemas", "jsonschema-draft-04.json"))
}
func v2SchemaJSONBytes() ([]byte, error) {
return assets.ReadFile(path.Join("schemas", "v2", "schema.json"))
}

View file

@ -27,7 +27,6 @@
// all relative $ref's will be resolved from there. // all relative $ref's will be resolved from there.
// //
// PathLoader injects a document loading method. By default, this resolves to the function provided by the SpecLoader package variable. // PathLoader injects a document loading method. By default, this resolves to the function provided by the SpecLoader package variable.
//
type ExpandOptions struct { type ExpandOptions struct {
RelativeBase string // the path to the root document to expand. This is a file, not a directory RelativeBase string // the path to the root document to expand. This is a file, not a directory
SkipSchemas bool // do not expand schemas, just paths, parameters and responses SkipSchemas bool // do not expand schemas, just paths, parameters and responses
@ -58,7 +57,7 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error {
if !options.SkipSchemas { if !options.SkipSchemas {
for key, definition := range spec.Definitions { for key, definition := range spec.Definitions {
parentRefs := make([]string, 0, 10) parentRefs := make([]string, 0, 10)
parentRefs = append(parentRefs, fmt.Sprintf("#/definitions/%s", key)) parentRefs = append(parentRefs, "#/definitions/"+key)
def, err := expandSchema(definition, parentRefs, resolver, specBasePath) def, err := expandSchema(definition, parentRefs, resolver, specBasePath)
if resolver.shouldStopOnError(err) { if resolver.shouldStopOnError(err) {
@ -103,15 +102,21 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error {
// baseForRoot loads in the cache the root document and produces a fake ".root" base path entry // baseForRoot loads in the cache the root document and produces a fake ".root" base path entry
// for further $ref resolution // for further $ref resolution
//
// Setting the cache is optional and this parameter may safely be left to nil.
func baseForRoot(root interface{}, cache ResolutionCache) string { func baseForRoot(root interface{}, cache ResolutionCache) string {
if root == nil {
return ""
}
// cache the root document to resolve $ref's // cache the root document to resolve $ref's
normalizedBase := normalizeBase(rootBase) normalizedBase := normalizeBase(rootBase)
if root == nil {
// ensure that we never leave a nil root: always cache the root base pseudo-document
cachedRoot, found := cache.Get(normalizedBase)
if found && cachedRoot != nil {
// the cache is already preloaded with a root
return normalizedBase
}
root = map[string]interface{}{}
}
cache.Set(normalizedBase, root) cache.Set(normalizedBase, root)
return normalizedBase return normalizedBase
@ -208,9 +213,21 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba
} }
if target.Ref.String() != "" { if target.Ref.String() != "" {
if !resolver.options.SkipSchemas {
return expandSchemaRef(target, parentRefs, resolver, basePath) return expandSchemaRef(target, parentRefs, resolver, basePath)
} }
// when "expand" with SkipSchema, we just rebase the existing $ref without replacing
// the full schema.
rebasedRef, err := NewRef(normalizeURI(target.Ref.String(), basePath))
if err != nil {
return nil, err
}
target.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID)
return &target, nil
}
for k := range target.Definitions { for k := range target.Definitions {
tt, err := expandSchema(target.Definitions[k], parentRefs, resolver, basePath) tt, err := expandSchema(target.Definitions[k], parentRefs, resolver, basePath)
if resolver.shouldStopOnError(err) { if resolver.shouldStopOnError(err) {
@ -520,21 +537,25 @@ func getRefAndSchema(input interface{}) (*Ref, *Schema, error) {
} }
func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePath string) error { func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePath string) error {
ref, _, err := getRefAndSchema(input) ref, sch, err := getRefAndSchema(input)
if err != nil { if err != nil {
return err return err
} }
if ref == nil { if ref == nil && sch == nil { // nothing to do
return nil return nil
} }
parentRefs := make([]string, 0, 10) parentRefs := make([]string, 0, 10)
if ref != nil {
// dereference this $ref
if err = resolver.deref(input, parentRefs, basePath); resolver.shouldStopOnError(err) { if err = resolver.deref(input, parentRefs, basePath); resolver.shouldStopOnError(err) {
return err return err
} }
ref, sch, _ := getRefAndSchema(input) ref, sch, _ = getRefAndSchema(input)
}
if ref.String() != "" { if ref.String() != "" {
transitiveResolver := resolver.transitiveResolver(basePath, *ref) transitiveResolver := resolver.transitiveResolver(basePath, *ref)
basePath = resolver.updateBasePath(transitiveResolver, basePath) basePath = resolver.updateBasePath(transitiveResolver, basePath)
@ -546,6 +567,7 @@ func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePa
if ref != nil { if ref != nil {
*ref = Ref{} *ref = Ref{}
} }
return nil return nil
} }
@ -555,38 +577,29 @@ func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePa
return ern return ern
} }
switch { if resolver.isCircular(&rebasedRef, basePath, parentRefs...) {
case resolver.isCircular(&rebasedRef, basePath, parentRefs...):
// this is a circular $ref: stop expansion // this is a circular $ref: stop expansion
if !resolver.options.AbsoluteCircularRef { if !resolver.options.AbsoluteCircularRef {
sch.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID) sch.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID)
} else { } else {
sch.Ref = rebasedRef sch.Ref = rebasedRef
} }
case !resolver.options.SkipSchemas:
// schema expanded to a $ref in another root
sch.Ref = rebasedRef
debugLog("rebased to: %s", sch.Ref.String())
default:
// skip schema expansion but rebase $ref to schema
sch.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID)
} }
} }
// $ref expansion or rebasing is performed by expandSchema below
if ref != nil { if ref != nil {
*ref = Ref{} *ref = Ref{}
} }
// expand schema // expand schema
if !resolver.options.SkipSchemas { // yes, we do it even if options.SkipSchema is true: we have to go down that rabbit hole and rebase nested $ref)
s, err := expandSchema(*sch, parentRefs, resolver, basePath) s, err := expandSchema(*sch, parentRefs, resolver, basePath)
if resolver.shouldStopOnError(err) { if resolver.shouldStopOnError(err) {
return err return err
} }
if s == nil {
// guard for when continuing on error if s != nil { // guard for when continuing on error
return nil
}
*sch = *s *sch = *s
} }

View file

@ -40,5 +40,5 @@ func repairURI(in string) (*url.URL, string) {
return u, "" return u, ""
} }
func fixWindowsURI(u *url.URL, in string) { func fixWindowsURI(_ *url.URL, _ string) {
} }

View file

@ -217,9 +217,12 @@ func (o *Operation) AddParam(param *Parameter) *Operation {
for i, p := range o.Parameters { for i, p := range o.Parameters {
if p.Name == param.Name && p.In == param.In { if p.Name == param.Name && p.In == param.In {
params := append(o.Parameters[:i], *param) params := make([]Parameter, 0, len(o.Parameters)+1)
params = append(params, o.Parameters[:i]...)
params = append(params, *param)
params = append(params, o.Parameters[i+1:]...) params = append(params, o.Parameters[i+1:]...)
o.Parameters = params o.Parameters = params
return o return o
} }
} }

View file

@ -84,25 +84,25 @@ type ParamProps struct {
// Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn). // Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn).
// //
// There are five possible parameter types. // There are five possible parameter types.
// * Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part // - Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part
// of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`, // of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`,
// the path parameter is `itemId`. // the path parameter is `itemId`.
// * Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`. // - Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`.
// * Header - Custom headers that are expected as part of the request. // - Header - Custom headers that are expected as part of the request.
// * Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be // - Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be
// _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for // _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for
// documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist // documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist
// together for the same operation. // together for the same operation.
// * Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or // - Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or
// `multipart/form-data` are used as the content type of the request (in Swagger's definition, // `multipart/form-data` are used as the content type of the request (in Swagger's definition,
// the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used // the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used
// to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be // to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be
// declared together with a body parameter for the same operation. Form parameters have a different format based on // declared together with a body parameter for the same operation. Form parameters have a different format based on
// the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4). // the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4).
// * `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload. // - `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload.
// For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple // For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple
// parameters that are being transferred. // parameters that are being transferred.
// * `multipart/form-data` - each parameter takes a section in the payload with an internal header. // - `multipart/form-data` - each parameter takes a section in the payload with an internal header.
// For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is // For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is
// `submit-name`. This type of form parameters is more commonly used for file transfers. // `submit-name`. This type of form parameters is more commonly used for file transfers.
// //

View file

@ -168,14 +168,7 @@ func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error)
normalized := normalizeBase(pth) normalized := normalizeBase(pth)
debugLog("loading doc from: %s", normalized) debugLog("loading doc from: %s", normalized)
unescaped, err := url.PathUnescape(normalized) data, fromCache := r.cache.Get(normalized)
if err != nil {
return nil, url.URL{}, false, err
}
u := url.URL{Path: unescaped}
data, fromCache := r.cache.Get(u.RequestURI())
if fromCache { if fromCache {
return data, toFetch, fromCache, nil return data, toFetch, fromCache, nil
} }

View file

@ -0,0 +1,149 @@
{
"id": "http://json-schema.org/draft-04/schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Core schema meta-schema",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
},
"positiveInteger": {
"type": "integer",
"minimum": 0
},
"positiveIntegerDefault0": {
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
},
"simpleTypes": {
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
},
"stringArray": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
}
},
"type": "object",
"properties": {
"id": {
"type": "string"
},
"$schema": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {},
"multipleOf": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "boolean",
"default": false
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "boolean",
"default": false
},
"maxLength": { "$ref": "#/definitions/positiveInteger" },
"minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" }
],
"default": {}
},
"items": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
},
"maxItems": { "$ref": "#/definitions/positiveInteger" },
"minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
"uniqueItems": {
"type": "boolean",
"default": false
},
"maxProperties": { "$ref": "#/definitions/positiveInteger" },
"minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
"required": { "$ref": "#/definitions/stringArray" },
"additionalProperties": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" }
],
"default": {}
},
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/stringArray" }
]
}
},
"enum": {
"type": "array",
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{ "$ref": "#/definitions/simpleTypes" },
{
"type": "array",
"items": { "$ref": "#/definitions/simpleTypes" },
"minItems": 1,
"uniqueItems": true
}
]
},
"format": { "type": "string" },
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" }
},
"dependencies": {
"exclusiveMaximum": [ "maximum" ],
"exclusiveMinimum": [ "minimum" ]
},
"default": {}
}

1607
vendor/github.com/go-openapi/spec/schemas/v2/schema.json generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,7 @@
const ( const (
// SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs // SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs
SwaggerSchemaURL = "http://swagger.io/v2/schema.json#" SwaggerSchemaURL = "http://swagger.io/v2/schema.json#"
// JSONSchemaURL the url for the json schema schema // JSONSchemaURL the url for the json schema
JSONSchemaURL = "http://json-schema.org/draft-04/schema#" JSONSchemaURL = "http://json-schema.org/draft-04/schema#"
) )
@ -41,7 +41,7 @@ func MustLoadJSONSchemaDraft04() *Schema {
// JSONSchemaDraft04 loads the json schema document for json shema draft04 // JSONSchemaDraft04 loads the json schema document for json shema draft04
func JSONSchemaDraft04() (*Schema, error) { func JSONSchemaDraft04() (*Schema, error) {
b, err := Asset("jsonschema-draft-04.json") b, err := jsonschemaDraft04JSONBytes()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -65,7 +65,7 @@ func MustLoadSwagger20Schema() *Schema {
// Swagger20Schema loads the swagger 2.0 schema from the embedded assets // Swagger20Schema loads the swagger 2.0 schema from the embedded assets
func Swagger20Schema() (*Schema, error) { func Swagger20Schema() (*Schema, error) {
b, err := Asset("v2/schema.json") b, err := v2SchemaJSONBytes()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -253,7 +253,7 @@ func (s SchemaOrBool) MarshalJSON() ([]byte, error) {
// UnmarshalJSON converts this bool or schema object from a JSON structure // UnmarshalJSON converts this bool or schema object from a JSON structure
func (s *SchemaOrBool) UnmarshalJSON(data []byte) error { func (s *SchemaOrBool) UnmarshalJSON(data []byte) error {
var nw SchemaOrBool var nw SchemaOrBool
if len(data) >= 4 { if len(data) > 0 {
if data[0] == '{' { if data[0] == '{' {
var sch Schema var sch Schema
if err := json.Unmarshal(data, &sch); err != nil { if err := json.Unmarshal(data, &sch); err != nil {
@ -261,7 +261,7 @@ func (s *SchemaOrBool) UnmarshalJSON(data []byte) error {
} }
nw.Schema = &sch nw.Schema = &sch
} }
nw.Allows = !(data[0] == 'f' && data[1] == 'a' && data[2] == 'l' && data[3] == 's' && data[4] == 'e') nw.Allows = !bytes.Equal(data, []byte("false"))
} }
*s = nw *s = nw
return nil return nil

View file

@ -1,8 +0,0 @@
//go:build !go1.19
// +build !go1.19
package spec
import "net/url"
var parseURL = url.Parse

View file

@ -1,6 +1,3 @@
//go:build go1.19
// +build go1.19
package spec package spec
import "net/url" import "net/url"

View file

@ -4,56 +4,58 @@ linters-settings:
golint: golint:
min-confidence: 0 min-confidence: 0
gocyclo: gocyclo:
min-complexity: 31 min-complexity: 45
maligned: maligned:
suggest-new: true suggest-new: true
dupl: dupl:
threshold: 100 threshold: 200
goconst: goconst:
min-len: 2 min-len: 2
min-occurrences: 4 min-occurrences: 3
linters: linters:
enable: enable-all: true
- revive disable:
- goimports - maligned
- gosec
- unparam - unparam
- unconvert - lll
- predeclared - gochecknoinits
- prealloc - gochecknoglobals
- misspell - funlen
- godox
# disable: - gocognit
# - maligned - whitespace
# - lll - wsl
# - gochecknoinits - wrapcheck
# - gochecknoglobals - testpackage
# - godox - nlreturn
# - gocognit - gomnd
# - whitespace - exhaustivestruct
# - wsl - goerr113
# - funlen - errorlint
# - wrapcheck - nestif
# - testpackage - godot
# - nlreturn - gofumpt
# - gofumpt - paralleltest
# - goerr113 - tparallel
# - gci - thelper
# - gomnd - ifshort
# - godot - exhaustruct
# - exhaustivestruct - varnamelen
# - paralleltest - gci
# - varnamelen - depguard
# - ireturn - errchkjson
# - exhaustruct - inamedparam
# #- thelper - nonamedreturns
- musttag
issues: - ireturn
exclude-rules: - forcetypeassert
- path: bson.go - cyclop
text: "should be .*ObjectID" # deprecated linters
linters: - deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint - golint
- stylecheck - nosnakecase

View file

@ -1,8 +1,7 @@
# Strfmt [![Build Status](https://travis-ci.org/go-openapi/strfmt.svg?branch=master)](https://travis-ci.org/go-openapi/strfmt) [![codecov](https://codecov.io/gh/go-openapi/strfmt/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/strfmt) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) # Strfmt [![Build Status](https://github.com/go-openapi/strfmt/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/strfmt/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/strfmt/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/strfmt)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/strfmt/master/LICENSE) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/strfmt/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/go-openapi/strfmt?status.svg)](http://godoc.org/github.com/go-openapi/strfmt) [![GoDoc](https://godoc.org/github.com/go-openapi/strfmt?status.svg)](http://godoc.org/github.com/go-openapi/strfmt)
[![GolangCI](https://golangci.com/badges/github.com/go-openapi/strfmt.svg)](https://golangci.com)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/strfmt)](https://goreportcard.com/report/github.com/go-openapi/strfmt) [![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/strfmt)](https://goreportcard.com/report/github.com/go-openapi/strfmt)
This package exposes a registry of data types to support string formats in the go-openapi toolkit. This package exposes a registry of data types to support string formats in the go-openapi toolkit.

View file

@ -39,10 +39,10 @@ func IsBSONObjectID(str string) bool {
// ObjectId represents a BSON object ID (alias to go.mongodb.org/mongo-driver/bson/primitive.ObjectID) // ObjectId represents a BSON object ID (alias to go.mongodb.org/mongo-driver/bson/primitive.ObjectID)
// //
// swagger:strfmt bsonobjectid // swagger:strfmt bsonobjectid
type ObjectId bsonprim.ObjectID //nolint:revive type ObjectId bsonprim.ObjectID //nolint:revive,stylecheck
// NewObjectId creates a ObjectId from a Hex String // NewObjectId creates a ObjectId from a Hex String
func NewObjectId(hex string) ObjectId { //nolint:revive func NewObjectId(hex string) ObjectId { //nolint:revive,stylecheck
oid, err := bsonprim.ObjectIDFromHex(hex) oid, err := bsonprim.ObjectIDFromHex(hex)
if err != nil { if err != nil {
panic(err) panic(err)
@ -135,7 +135,7 @@ func (id *ObjectId) UnmarshalBSON(data []byte) error {
// BSON document if the error is nil. // BSON document if the error is nil.
func (id ObjectId) MarshalBSONValue() (bsontype.Type, []byte, error) { func (id ObjectId) MarshalBSONValue() (bsontype.Type, []byte, error) {
oid := bsonprim.ObjectID(id) oid := bsonprim.ObjectID(id)
return bsontype.ObjectID, oid[:], nil return bson.TypeObjectID, oid[:], nil
} }
// UnmarshalBSONValue is an interface implemented by types that can unmarshal a // UnmarshalBSONValue is an interface implemented by types that can unmarshal a

View file

@ -25,6 +25,7 @@
"strings" "strings"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
) )
@ -57,24 +58,35 @@
// - long top-level domain names (e.g. example.london) are permitted // - long top-level domain names (e.g. example.london) are permitted
// - symbol unicode points are permitted (e.g. emoji) (not for top-level domain) // - symbol unicode points are permitted (e.g. emoji) (not for top-level domain)
HostnamePattern = `^([a-zA-Z0-9\p{S}\p{L}]((-?[a-zA-Z0-9\p{S}\p{L}]{0,62})?)|([a-zA-Z0-9\p{S}\p{L}](([a-zA-Z0-9-\p{S}\p{L}]{0,61}[a-zA-Z0-9\p{S}\p{L}])?)(\.)){1,}([a-zA-Z\p{L}]){2,63})$` HostnamePattern = `^([a-zA-Z0-9\p{S}\p{L}]((-?[a-zA-Z0-9\p{S}\p{L}]{0,62})?)|([a-zA-Z0-9\p{S}\p{L}](([a-zA-Z0-9-\p{S}\p{L}]{0,61}[a-zA-Z0-9\p{S}\p{L}])?)(\.)){1,}([a-zA-Z\p{L}]){2,63})$`
// UUIDPattern Regex for UUID that allows uppercase
UUIDPattern = `(?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$`
// UUID3Pattern Regex for UUID3 that allows uppercase
UUID3Pattern = `(?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$`
// UUID4Pattern Regex for UUID4 that allows uppercase
UUID4Pattern = `(?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$`
// UUID5Pattern Regex for UUID5 that allows uppercase
UUID5Pattern = `(?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$`
// json null type // json null type
jsonNull = "null" jsonNull = "null"
) )
const (
// UUIDPattern Regex for UUID that allows uppercase
//
// Deprecated: strfmt no longer uses regular expressions to validate UUIDs.
UUIDPattern = `(?i)(^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$)|(^[0-9a-f]{32}$)`
// UUID3Pattern Regex for UUID3 that allows uppercase
//
// Deprecated: strfmt no longer uses regular expressions to validate UUIDs.
UUID3Pattern = `(?i)(^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$)|(^[0-9a-f]{12}3[0-9a-f]{3}?[0-9a-f]{16}$)`
// UUID4Pattern Regex for UUID4 that allows uppercase
//
// Deprecated: strfmt no longer uses regular expressions to validate UUIDs.
UUID4Pattern = `(?i)(^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$)|(^[0-9a-f]{12}4[0-9a-f]{3}[89ab][0-9a-f]{15}$)`
// UUID5Pattern Regex for UUID5 that allows uppercase
//
// Deprecated: strfmt no longer uses regular expressions to validate UUIDs.
UUID5Pattern = `(?i)(^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$)|(^[0-9a-f]{12}5[0-9a-f]{3}[89ab][0-9a-f]{15}$)`
)
var ( var (
rxHostname = regexp.MustCompile(HostnamePattern) rxHostname = regexp.MustCompile(HostnamePattern)
rxUUID = regexp.MustCompile(UUIDPattern)
rxUUID3 = regexp.MustCompile(UUID3Pattern)
rxUUID4 = regexp.MustCompile(UUID4Pattern)
rxUUID5 = regexp.MustCompile(UUID5Pattern)
) )
// IsHostname returns true when the string is a valid hostname // IsHostname returns true when the string is a valid hostname
@ -99,24 +111,28 @@ func IsHostname(str string) bool {
return valid return valid
} }
// IsUUID returns true is the string matches a UUID, upper case is allowed // IsUUID returns true is the string matches a UUID (in any version, including v6 and v7), upper case is allowed
func IsUUID(str string) bool { func IsUUID(str string) bool {
return rxUUID.MatchString(str) _, err := uuid.Parse(str)
return err == nil
} }
// IsUUID3 returns true is the string matches a UUID, upper case is allowed // IsUUID3 returns true is the string matches a UUID v3, upper case is allowed
func IsUUID3(str string) bool { func IsUUID3(str string) bool {
return rxUUID3.MatchString(str) id, err := uuid.Parse(str)
return err == nil && id.Version() == uuid.Version(3)
} }
// IsUUID4 returns true is the string matches a UUID, upper case is allowed // IsUUID4 returns true is the string matches a UUID v4, upper case is allowed
func IsUUID4(str string) bool { func IsUUID4(str string) bool {
return rxUUID4.MatchString(str) id, err := uuid.Parse(str)
return err == nil && id.Version() == uuid.Version(4)
} }
// IsUUID5 returns true is the string matches a UUID, upper case is allowed // IsUUID5 returns true is the string matches a UUID v5, upper case is allowed
func IsUUID5(str string) bool { func IsUUID5(str string) bool {
return rxUUID5.MatchString(str) id, err := uuid.Parse(str)
return err == nil && id.Version() == uuid.Version(5)
} }
// IsEmail validates an email address. // IsEmail validates an email address.

View file

@ -16,6 +16,7 @@
import ( import (
"encoding" "encoding"
stderrors "errors"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@ -94,7 +95,7 @@ func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry {
} }
// MapStructureHookFunc is a decode hook function for mapstructure // MapStructureHookFunc is a decode hook function for mapstructure
func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc { //nolint:gocyclo,cyclop func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc {
return func(from reflect.Type, to reflect.Type, obj interface{}) (interface{}, error) { return func(from reflect.Type, to reflect.Type, obj interface{}) (interface{}, error) {
if from.Kind() != reflect.String { if from.Kind() != reflect.String {
return obj, nil return obj, nil
@ -117,7 +118,7 @@ func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc { //
case "datetime": case "datetime":
input := data input := data
if len(input) == 0 { if len(input) == 0 {
return nil, fmt.Errorf("empty string is an invalid datetime format") return nil, stderrors.New("empty string is an invalid datetime format")
} }
return ParseDateTime(input) return ParseDateTime(input)
case "duration": case "duration":

View file

@ -76,6 +76,8 @@ func IsDateTime(str string) bool {
ISO8601TimeWithReducedPrecisionLocaltime = "2006-01-02T15:04" ISO8601TimeWithReducedPrecisionLocaltime = "2006-01-02T15:04"
// ISO8601TimeUniversalSortableDateTimePattern represents a ISO8601 universal sortable date time pattern. // ISO8601TimeUniversalSortableDateTimePattern represents a ISO8601 universal sortable date time pattern.
ISO8601TimeUniversalSortableDateTimePattern = "2006-01-02 15:04:05" ISO8601TimeUniversalSortableDateTimePattern = "2006-01-02 15:04:05"
// short form of ISO8601TimeUniversalSortableDateTimePattern
ISO8601TimeUniversalSortableDateTimePatternShortForm = "2006-01-02"
// DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6 // DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$` DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
) )
@ -84,7 +86,7 @@ func IsDateTime(str string) bool {
rxDateTime = regexp.MustCompile(DateTimePattern) rxDateTime = regexp.MustCompile(DateTimePattern)
// DateTimeFormats is the collection of formats used by ParseDateTime() // DateTimeFormats is the collection of formats used by ParseDateTime()
DateTimeFormats = []string{RFC3339Micro, RFC3339MicroNoColon, RFC3339Millis, RFC3339MillisNoColon, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime, ISO8601TimeWithReducedPrecision, ISO8601TimeWithReducedPrecisionLocaltime, ISO8601TimeUniversalSortableDateTimePattern} DateTimeFormats = []string{RFC3339Micro, RFC3339MicroNoColon, RFC3339Millis, RFC3339MillisNoColon, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime, ISO8601TimeWithReducedPrecision, ISO8601TimeWithReducedPrecisionLocaltime, ISO8601TimeUniversalSortableDateTimePattern, ISO8601TimeUniversalSortableDateTimePatternShortForm}
// MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds) // MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
MarshalFormat = RFC3339Millis MarshalFormat = RFC3339Millis
@ -245,7 +247,7 @@ func (t DateTime) MarshalBSONValue() (bsontype.Type, []byte, error) {
buf := make([]byte, 8) buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, uint64(i64)) binary.LittleEndian.PutUint64(buf, uint64(i64))
return bsontype.DateTime, buf, nil return bson.TypeDateTime, buf, nil
} }
// UnmarshalBSONValue is an interface implemented by types that can unmarshal a // UnmarshalBSONValue is an interface implemented by types that can unmarshal a
@ -253,7 +255,7 @@ func (t DateTime) MarshalBSONValue() (bsontype.Type, []byte, error) {
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it // assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning. // wishes to retain the data after returning.
func (t *DateTime) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error { func (t *DateTime) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
if tpe == bsontype.Null { if tpe == bson.TypeNull {
*t = DateTime{} *t = DateTime{}
return nil return nil
} }

View file

@ -2,3 +2,4 @@ secrets.yml
vendor vendor
Godeps Godeps
.idea .idea
*.out

View file

@ -4,14 +4,14 @@ linters-settings:
golint: golint:
min-confidence: 0 min-confidence: 0
gocyclo: gocyclo:
min-complexity: 25 min-complexity: 45
maligned: maligned:
suggest-new: true suggest-new: true
dupl: dupl:
threshold: 100 threshold: 200
goconst: goconst:
min-len: 3 min-len: 3
min-occurrences: 2 min-occurrences: 3
linters: linters:
enable-all: true enable-all: true
@ -20,35 +20,41 @@ linters:
- lll - lll
- gochecknoinits - gochecknoinits
- gochecknoglobals - gochecknoglobals
- nlreturn - funlen
- testpackage - godox
- gocognit
- whitespace
- wsl
- wrapcheck - wrapcheck
- testpackage
- nlreturn
- gomnd - gomnd
- exhaustive
- exhaustivestruct - exhaustivestruct
- goerr113 - goerr113
- wsl - errorlint
- whitespace
- gofumpt
- godot
- nestif - nestif
- godox - godot
- funlen - gofumpt
- gci
- gocognit
- paralleltest - paralleltest
- tparallel
- thelper - thelper
- ifshort - ifshort
- gomoddirectives
- cyclop
- forcetypeassert
- ireturn
- tagliatelle
- varnamelen
- goimports
- tenv
- golint
- exhaustruct - exhaustruct
- nilnil - varnamelen
- gci
- depguard
- errchkjson
- inamedparam
- nonamedreturns - nonamedreturns
- musttag
- ireturn
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase - nosnakecase

Some files were not shown because too many files have changed in this diff Show more