Update all dependencies

Note: should we ditch vendoring?

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
Gabriel Adrian Samfira 2025-09-29 10:20:26 +00:00 committed by Gabriel
parent 22fde8d30e
commit 0093393bc3
371 changed files with 91052 additions and 25816 deletions

77
go.mod
View file

@ -8,10 +8,10 @@ require (
github.com/cloudbase/garm-provider-common v0.1.7
github.com/felixge/httpsnoop v1.0.4
github.com/gdamore/tcell/v2 v2.9.0
github.com/go-openapi/errors v0.22.2
github.com/go-openapi/runtime v0.28.0
github.com/go-openapi/strfmt v0.23.0
github.com/go-openapi/swag v0.24.1
github.com/go-openapi/errors v0.22.3
github.com/go-openapi/runtime v0.29.0
github.com/go-openapi/strfmt v0.24.0
github.com/go-openapi/swag v0.25.1
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/google/go-github/v72 v72.0.0
github.com/google/uuid v1.6.0
@ -21,7 +21,7 @@ require (
github.com/jedib0t/go-pretty/v6 v6.6.8
github.com/manifoldco/promptui v0.9.0
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354
github.com/prometheus/client_golang v1.23.0
github.com/prometheus/client_golang v1.23.2
github.com/rivo/tview v0.42.0
github.com/spf13/cobra v1.10.1
github.com/stretchr/testify v1.11.1
@ -47,58 +47,57 @@ require (
github.com/gdamore/encoding v1.0.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/jsonpointer v0.21.2 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/loads v0.22.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/swag/cmdutils v0.24.0 // indirect
github.com/go-openapi/swag/conv v0.24.0 // indirect
github.com/go-openapi/swag/fileutils v0.24.0 // indirect
github.com/go-openapi/swag/jsonname v0.24.0 // indirect
github.com/go-openapi/swag/jsonutils v0.24.0 // indirect
github.com/go-openapi/swag/loading v0.24.0 // indirect
github.com/go-openapi/swag/mangling v0.24.0 // indirect
github.com/go-openapi/swag/netutils v0.24.0 // indirect
github.com/go-openapi/swag/stringutils v0.24.0 // indirect
github.com/go-openapi/swag/typeutils v0.24.0 // indirect
github.com/go-openapi/swag/yamlutils v0.24.0 // indirect
github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-openapi/analysis v0.24.0 // indirect
github.com/go-openapi/jsonpointer v0.22.1 // indirect
github.com/go-openapi/jsonreference v0.21.2 // indirect
github.com/go-openapi/loads v0.23.1 // indirect
github.com/go-openapi/spec v0.22.0 // indirect
github.com/go-openapi/swag/cmdutils v0.25.1 // indirect
github.com/go-openapi/swag/conv v0.25.1 // indirect
github.com/go-openapi/swag/fileutils v0.25.1 // indirect
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
github.com/go-openapi/swag/loading v0.25.1 // indirect
github.com/go-openapi/swag/mangling v0.25.1 // indirect
github.com/go-openapi/swag/netutils v0.25.1 // indirect
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
github.com/go-openapi/swag/typeutils v0.25.1 // indirect
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
github.com/go-openapi/validate v0.25.0 // indirect
github.com/go-sql-driver/mysql v1.9.3 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-sqlite3 v1.14.31 // indirect
github.com/minio/sio v0.4.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mattn/go-runewidth v0.0.17 // indirect
github.com/mattn/go-sqlite3 v1.14.32 // indirect
github.com/minio/sio v0.4.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 // indirect
go.mongodb.org/mongo-driver v1.17.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
golang.org/x/net v0.43.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.29.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
google.golang.org/protobuf v1.36.9 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

165
go.sum
View file

@ -36,50 +36,54 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
github.com/go-openapi/errors v0.22.2 h1:rdxhzcBUazEcGccKqbY1Y7NS8FDcMyIRr0934jrYnZg=
github.com/go-openapi/errors v0.22.2/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0=
github.com/go-openapi/jsonpointer v0.21.2 h1:AqQaNADVwq/VnkCmQg6ogE+M3FOsKTytwges0JdwVuA=
github.com/go-openapi/jsonpointer v0.21.2/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco=
github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs=
github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ=
github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc=
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
github.com/go-openapi/swag v0.24.1 h1:DPdYTZKo6AQCRqzwr/kGkxJzHhpKxZ9i/oX0zag+MF8=
github.com/go-openapi/swag v0.24.1/go.mod h1:sm8I3lCPlspsBBwUm1t5oZeWZS0s7m/A+Psg0ooRU0A=
github.com/go-openapi/swag/cmdutils v0.24.0 h1:KlRCffHwXFI6E5MV9n8o8zBRElpY4uK4yWyAMWETo9I=
github.com/go-openapi/swag/cmdutils v0.24.0/go.mod h1:uxib2FAeQMByyHomTlsP8h1TtPd54Msu2ZDU/H5Vuf8=
github.com/go-openapi/swag/conv v0.24.0 h1:ejB9+7yogkWly6pnruRX45D1/6J+ZxRu92YFivx54ik=
github.com/go-openapi/swag/conv v0.24.0/go.mod h1:jbn140mZd7EW2g8a8Y5bwm8/Wy1slLySQQ0ND6DPc2c=
github.com/go-openapi/swag/fileutils v0.24.0 h1:U9pCpqp4RUytnD689Ek/N1d2N/a//XCeqoH508H5oak=
github.com/go-openapi/swag/fileutils v0.24.0/go.mod h1:3SCrCSBHyP1/N+3oErQ1gP+OX1GV2QYFSnrTbzwli90=
github.com/go-openapi/swag/jsonname v0.24.0 h1:2wKS9bgRV/xB8c62Qg16w4AUiIrqqiniJFtZGi3dg5k=
github.com/go-openapi/swag/jsonname v0.24.0/go.mod h1:GXqrPzGJe611P7LG4QB9JKPtUZ7flE4DOVechNaDd7Q=
github.com/go-openapi/swag/jsonutils v0.24.0 h1:F1vE1q4pg1xtO3HTyJYRmEuJ4jmIp2iZ30bzW5XgZts=
github.com/go-openapi/swag/jsonutils v0.24.0/go.mod h1:vBowZtF5Z4DDApIoxcIVfR8v0l9oq5PpYRUuteVu6f0=
github.com/go-openapi/swag/loading v0.24.0 h1:ln/fWTwJp2Zkj5DdaX4JPiddFC5CHQpvaBKycOlceYc=
github.com/go-openapi/swag/loading v0.24.0/go.mod h1:gShCN4woKZYIxPxbfbyHgjXAhO61m88tmjy0lp/LkJk=
github.com/go-openapi/swag/mangling v0.24.0 h1:PGOQpViCOUroIeak/Uj/sjGAq9LADS3mOyjznmHy2pk=
github.com/go-openapi/swag/mangling v0.24.0/go.mod h1:Jm5Go9LHkycsz0wfoaBDkdc4CkpuSnIEf62brzyCbhc=
github.com/go-openapi/swag/netutils v0.24.0 h1:Bz02HRjYv8046Ycg/w80q3g9QCWeIqTvlyOjQPDjD8w=
github.com/go-openapi/swag/netutils v0.24.0/go.mod h1:WRgiHcYTnx+IqfMCtu0hy9oOaPR0HnPbmArSRN1SkZM=
github.com/go-openapi/swag/stringutils v0.24.0 h1:i4Z/Jawf9EvXOLUbT97O0HbPUja18VdBxeadyAqS1FM=
github.com/go-openapi/swag/stringutils v0.24.0/go.mod h1:5nUXB4xA0kw2df5PRipZDslPJgJut+NjL7D25zPZ/4w=
github.com/go-openapi/swag/typeutils v0.24.0 h1:d3szEGzGDf4L2y1gYOSSLeK6h46F+zibnEas2Jm/wIw=
github.com/go-openapi/swag/typeutils v0.24.0/go.mod h1:q8C3Kmk/vh2VhpCLaoR2MVWOGP8y7Jc8l82qCTd1DYI=
github.com/go-openapi/swag/yamlutils v0.24.0 h1:bhw4894A7Iw6ne+639hsBNRHg9iZg/ISrOVr+sJGp4c=
github.com/go-openapi/swag/yamlutils v0.24.0/go.mod h1:DpKv5aYuaGm/sULePoeiG8uwMpZSfReo1HR3Ik0yaG8=
github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
github.com/go-openapi/analysis v0.24.0 h1:vE/VFFkICKyYuTWYnplQ+aVr45vlG6NcZKC7BdIXhsA=
github.com/go-openapi/analysis v0.24.0/go.mod h1:GLyoJA+bvmGGaHgpfeDh8ldpGo69fAJg7eeMDMRCIrw=
github.com/go-openapi/errors v0.22.3 h1:k6Hxa5Jg1TUyZnOwV2Lh81j8ayNw5VVYLvKrp4zFKFs=
github.com/go-openapi/errors v0.22.3/go.mod h1:+WvbaBBULWCOna//9B9TbLNGSFOfF8lY9dw4hGiEiKQ=
github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=
github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=
github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU=
github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ=
github.com/go-openapi/loads v0.23.1 h1:H8A0dX2KDHxDzc797h0+uiCZ5kwE2+VojaQVaTlXvS0=
github.com/go-openapi/loads v0.23.1/go.mod h1:hZSXkyACCWzWPQqizAv/Ye0yhi2zzHwMmoXQ6YQml44=
github.com/go-openapi/runtime v0.29.0 h1:Y7iDTFarS9XaFQ+fA+lBLngMwH6nYfqig1G+pHxMRO0=
github.com/go-openapi/runtime v0.29.0/go.mod h1:52HOkEmLL/fE4Pg3Kf9nxc9fYQn0UsIWyGjGIJE9dkg=
github.com/go-openapi/spec v0.22.0 h1:xT/EsX4frL3U09QviRIZXvkh80yibxQmtoEvyqug0Tw=
github.com/go-openapi/spec v0.22.0/go.mod h1:K0FhKxkez8YNS94XzF8YKEMULbFrRw4m15i2YUht4L0=
github.com/go-openapi/strfmt v0.24.0 h1:dDsopqbI3wrrlIzeXRbqMihRNnjzGC+ez4NQaAAJLuc=
github.com/go-openapi/strfmt v0.24.0/go.mod h1:Lnn1Bk9rZjXxU9VMADbEEOo7D7CDyKGLsSKekhFr7s4=
github.com/go-openapi/swag v0.25.1 h1:6uwVsx+/OuvFVPqfQmOOPsqTcm5/GkBhNwLqIR916n8=
github.com/go-openapi/swag v0.25.1/go.mod h1:bzONdGlT0fkStgGPd3bhZf1MnuPkf2YAys6h+jZipOo=
github.com/go-openapi/swag/cmdutils v0.25.1 h1:nDke3nAFDArAa631aitksFGj2omusks88GF1VwdYqPY=
github.com/go-openapi/swag/cmdutils v0.25.1/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
github.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0=
github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs=
github.com/go-openapi/swag/fileutils v0.25.1 h1:rSRXapjQequt7kqalKXdcpIegIShhTPXx7yw0kek2uU=
github.com/go-openapi/swag/fileutils v0.25.1/go.mod h1:+NXtt5xNZZqmpIpjqcujqojGFek9/w55b3ecmOdtg8M=
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
github.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8=
github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1 h1:DSQGcdB6G0N9c/KhtpYc71PzzGEIc/fZ1no35x4/XBY=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1/go.mod h1:kjmweouyPwRUEYMSrbAidoLMGeJ5p6zdHi9BgZiqmsg=
github.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw=
github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc=
github.com/go-openapi/swag/mangling v0.25.1 h1:XzILnLzhZPZNtmxKaz/2xIGPQsBsvmCjrJOWGNz/ync=
github.com/go-openapi/swag/mangling v0.25.1/go.mod h1:CdiMQ6pnfAgyQGSOIYnZkXvqhnnwOn997uXZMAd/7mQ=
github.com/go-openapi/swag/netutils v0.25.1 h1:2wFLYahe40tDUHfKT1GRC4rfa5T1B4GWZ+msEFA4Fl4=
github.com/go-openapi/swag/netutils v0.25.1/go.mod h1:CAkkvqnUJX8NV96tNhEQvKz8SQo2KF0f7LleiJwIeRE=
github.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw=
github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg=
github.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA=
github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8=
github.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk=
github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg=
github.com/go-openapi/validate v0.25.0 h1:JD9eGX81hDTjoY3WOzh6WqxVBVl7xjsLnvDo1GL5WPU=
github.com/go-openapi/validate v0.25.0/go.mod h1:SUY7vKrN5FiwK6LyvSwKjDfLNirSfWwHNgxd2l29Mmw=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
@ -119,8 +123,6 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
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/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -129,62 +131,55 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.31 h1:ldt6ghyPJsokUIlksH63gWZkG6qVGeEAu4zLeS4aVZM=
github.com/mattn/go-sqlite3 v1.14.31/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ=
github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA=
github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/minio/sio v0.4.1 h1:EMe3YBC1nf+sRQia65Rutxi+Z554XPV0dt8BIBA+a/0=
github.com/minio/sio v0.4.1/go.mod h1:oBSjJeGbBdRMZZwna07sX9EFzZy+ywu5aofRiV1g79I=
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/minio/sio v0.4.2 h1:+ayQoaniewWpKzz6b27F075b+q1HJajQr8ViG9KFZwA=
github.com/minio/sio v0.4.2/go.mod h1:VgJIPc0yCY+2IeI39pkf91yXjyx2geyBN1N+TbB1Rws=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
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.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c=
github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI=
@ -192,18 +187,22 @@ github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIf
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
@ -216,8 +215,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -254,8 +253,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -1,61 +1,75 @@
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
version: "2"
linters:
enable-all: true
default: all
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
- cyclop
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- errorlint
- exhaustruct
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase
- funlen
- gochecknoglobals
- gochecknoinits
- gocognit
- godot
- godox
- gosmopolitan
- inamedparam
#- intrange # disabled while < go1.22
- ireturn
- lll
- musttag
- nestif
- nlreturn
- noinlineerr
- nonamedreturns
- paralleltest
- recvcheck
- testpackage
- thelper
- tparallel
- unparam
- varnamelen
- whitespace
- wrapcheck
- wsl
- wsl_v5
settings:
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
gocyclo:
min-complexity: 45
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
# Maximum issues count per one linter.
# Set to 0 to disable.
# Default: 50
max-issues-per-linter: 0
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 0

File diff suppressed because it is too large Load diff

53
vendor/github.com/go-openapi/analysis/errors.go generated vendored Normal file
View file

@ -0,0 +1,53 @@
package analysis
import (
"errors"
"fmt"
)
type analysisError string
const (
ErrAnalysis analysisError = "analysis error"
ErrNoSchema analysisError = "no schema to analyze"
)
func (e analysisError) Error() string {
return string(e)
}
func ErrAtKey(key string, err error) error {
return errors.Join(
fmt.Errorf("key %s: %w", key, err),
ErrAnalysis,
)
}
func ErrInvalidRef(key string) error {
return fmt.Errorf("invalid reference: %q: %w", key, ErrAnalysis)
}
func ErrInvalidParameterRef(key string) error {
return fmt.Errorf("resolved reference is not a parameter: %q: %w", key, ErrAnalysis)
}
func ErrResolveSchema(err error) error {
return errors.Join(
fmt.Errorf("could not resolve schema: %w", err),
ErrAnalysis,
)
}
func ErrRewriteRef(key string, target any, err error) error {
return errors.Join(
fmt.Errorf("failed to rewrite ref for key %q at %v: %w", key, target, err),
ErrAnalysis,
)
}
func ErrInlineDefinition(key string, err error) error {
return errors.Join(
fmt.Errorf("error while creating definition %q from inline schema: %w", key, err),
ErrAnalysis,
)
}

View file

@ -72,7 +72,7 @@ func FixEmptyDescs(rs *spec.Responses) {
// Response object if it doesn't already have one and isn't a
// ref. No-op on nil input.
func FixEmptyDesc(rs *spec.Response) {
if rs == nil || rs.Description != "" || rs.Ref.Ref.GetURL() != nil {
if rs == nil || rs.Description != "" || rs.Ref.GetURL() != nil {
return
}
rs.Description = "(empty)"

View file

@ -15,7 +15,6 @@
package analysis
import (
"fmt"
"log"
"path"
"sort"
@ -52,9 +51,9 @@ type context struct {
func newContext() *context {
return &context{
newRefs: make(map[string]*newRef, 150),
newRefs: make(map[string]*newRef, allocMediumMap),
warnings: make([]string, 0),
resolved: make(map[string]string, 50),
resolved: make(map[string]string, allocMediumMap),
}
}
@ -251,7 +250,7 @@ func nameInlinedSchemas(opts *FlattenOpts) error {
asch, err := Schema(SchemaOpts{Schema: sch.Schema, Root: opts.Swagger(), BasePath: opts.BasePath})
if err != nil {
return fmt.Errorf("schema analysis [%s]: %w", key, err)
return ErrAtKey(key, err)
}
if asch.isAnalyzedAsComplex() { // move complex schemas to definitions
@ -320,7 +319,7 @@ func importNewRef(entry sortref.RefRevIdx, refStr string, opts *FlattenOpts) err
sch, err := spec.ResolveRefWithBase(opts.Swagger(), &entry.Ref, opts.ExpandOpts(false))
if err != nil {
return fmt.Errorf("could not resolve schema: %w", err)
return ErrResolveSchema(err)
}
// at this stage only $ref analysis matters
@ -335,7 +334,7 @@ func importNewRef(entry sortref.RefRevIdx, refStr string, opts *FlattenOpts) err
// now rewrite those refs with rebase
for key, ref := range partialAnalyzer.references.allRefs {
if err := replace.UpdateRef(sch, key, spec.MustCreateRef(normalize.RebaseRef(entry.Ref.String(), ref.String()))); err != nil {
return fmt.Errorf("failed to rewrite ref for key %q at %s: %w", key, entry.Ref.String(), err)
return ErrRewriteRef(key, entry.Ref.String(), err)
}
}
@ -429,7 +428,7 @@ func importExternalReferences(opts *FlattenOpts) (bool, error) {
ref := spec.MustCreateRef(r.path)
sch, err := spec.ResolveRefWithBase(opts.Swagger(), &ref, opts.ExpandOpts(false))
if err != nil {
return false, fmt.Errorf("could not resolve schema: %w", err)
return false, ErrResolveSchema(err)
}
r.schema = sch
@ -643,7 +642,7 @@ func stripOAIGenForRef(opts *FlattenOpts, k string, r *newRef) (bool, error) {
}
debugLog("re-inlined schema: parent: %s, %t", pr[0], asch.isAnalyzedAsComplex())
replacedWithComplex = replacedWithComplex || !(path.Dir(pr[0]) == definitionsPath) && asch.isAnalyzedAsComplex()
replacedWithComplex = replacedWithComplex || path.Dir(pr[0]) != definitionsPath && asch.isAnalyzedAsComplex()
}
return replacedWithComplex, nil
@ -666,7 +665,7 @@ func namePointers(opts *FlattenOpts) error {
result, err := replace.DeepestRef(opts.Swagger(), opts.ExpandOpts(false), ref)
if err != nil {
return fmt.Errorf("at %s, %w", k, err)
return ErrAtKey(k, err)
}
replacingRef := result.Ref
@ -697,7 +696,7 @@ func namePointers(opts *FlattenOpts) error {
// update current replacement, which may have been updated by previous changes of deeper elements
result, erd := replace.DeepestRef(opts.Swagger(), opts.ExpandOpts(false), v.Ref)
if erd != nil {
return fmt.Errorf("at %s, %w", key, erd)
return ErrAtKey(key, erd)
}
if opts.flattenContext != nil {
@ -743,9 +742,9 @@ func flattenAnonPointer(key string, v SchemaRef, refsToReplace map[string]Schema
// qualify the expanded schema
asch, ers := Schema(SchemaOpts{Schema: v.Schema, Root: opts.Swagger(), BasePath: opts.BasePath})
if ers != nil {
return fmt.Errorf("schema analysis [%s]: %w", key, ers)
return ErrAtKey(key, ers)
}
callers := make([]string, 0, 64)
callers := make([]string, 0, allocMediumMap)
debugLog("looking for callers")
@ -753,7 +752,7 @@ func flattenAnonPointer(key string, v SchemaRef, refsToReplace map[string]Schema
for k, w := range an.references.allRefs {
r, err := replace.DeepestRef(opts.Swagger(), opts.ExpandOpts(false), w)
if err != nil {
return fmt.Errorf("at %s, %w", key, err)
return ErrAtKey(key, err)
}
if opts.flattenContext != nil {

View file

@ -11,7 +11,7 @@ import (
"github.com/go-openapi/analysis/internal/flatten/schutils"
"github.com/go-openapi/analysis/internal/flatten/sortref"
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/mangling"
)
// InlineSchemaNamer finds a new name for an inlined type
@ -43,7 +43,7 @@ func (isn *InlineSchemaNamer) Name(key string, schema *spec.Schema, aschema *Ana
debugLog("rewriting schema to ref: key=%s with new name: %s", key, newName)
if err := replace.RewriteSchemaToRef(isn.Spec, key,
spec.MustCreateRef(path.Join(definitionsPath, newName))); err != nil {
return fmt.Errorf("error while creating definition %q from inline schema: %w", newName, err)
return ErrInlineDefinition(newName, err)
}
// rewrite any dependent $ref pointing to this place,
@ -54,7 +54,7 @@ func (isn *InlineSchemaNamer) Name(key string, schema *spec.Schema, aschema *Ana
for k, v := range an.references.allRefs {
r, erd := replace.DeepestRef(isn.opts.Swagger(), isn.opts.ExpandOpts(false), v)
if erd != nil {
return fmt.Errorf("at %s, %w", k, erd)
return ErrAtKey(k, erd)
}
if isn.opts.flattenContext != nil {
@ -227,10 +227,15 @@ func namesForOperation(parts sortref.SplitKey, operations map[string]operations.
return baseNames, startIndex
}
const (
minStartIndex = 2
minSegments = 2
)
func namesForDefinition(parts sortref.SplitKey) ([][]string, int) {
nm := parts.DefinitionName()
if nm != "" {
return [][]string{{parts.DefinitionName()}}, 2
return [][]string{{parts.DefinitionName()}}, minStartIndex
}
return [][]string{}, 0
@ -239,7 +244,7 @@ func namesForDefinition(parts sortref.SplitKey) ([][]string, int) {
// partAdder knows how to interpret a schema when it comes to build a name from parts
func partAdder(aschema *AnalyzedSchema) sortref.PartAdder {
return func(part string) []string {
segments := make([]string, 0, 2)
segments := make([]string, 0, minSegments)
if part == "items" || part == "additionalItems" {
if aschema.IsTuple || aschema.IsTupleWithExtra {
@ -265,8 +270,9 @@ func mangler(o *FlattenOpts) func(string) string {
if o.KeepNames {
return func(in string) string { return in }
}
mangler := mangling.NewNameMangler()
return swag.ToJSONName
return mangler.ToJSONName
}
func nameFromRef(ref spec.Ref, o *FlattenOpts) string {

View file

@ -2,12 +2,13 @@ package operations
import (
"path"
"slices"
"sort"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/mangling"
)
// AllOpRefsByRef returns an index of sortable operations
@ -50,12 +51,13 @@ type Provider interface {
// GatherOperations builds a map of sorted operations from a spec
func GatherOperations(specDoc Provider, operationIDs []string) map[string]OpRef {
var oprefs OpRefs
mangler := mangling.NewNameMangler()
for method, pathItem := range specDoc.Operations() {
for pth, operation := range pathItem {
vv := *operation
oprefs = append(oprefs, OpRef{
Key: swag.ToGoName(strings.ToLower(method) + " " + pth),
Key: mangler.ToGoName(strings.ToLower(method) + " " + pth),
Method: method,
Path: pth,
ID: vv.ID,
@ -79,7 +81,7 @@ func GatherOperations(specDoc Provider, operationIDs []string) map[string]OpRef
nm = opr.Key
}
if len(operationIDs) == 0 || swag.ContainsStrings(operationIDs, opr.ID) || swag.ContainsStrings(operationIDs, nm) {
if len(operationIDs) == 0 || slices.Contains(operationIDs, opr.ID) || slices.Contains(operationIDs, nm) {
opr.ID = nm
opr.Op.ID = nm
operations[nm] = opr

View file

@ -0,0 +1,61 @@
package replace
import (
"errors"
"fmt"
)
type replaceError string
const (
ErrReplace replaceError = "flatten replace error"
ErrUnexpectedType replaceError = "unexpected type used in getPointerFromKey"
)
func (e replaceError) Error() string {
return string(e)
}
func ErrNoSchemaWithRef(key string, value any) error {
return fmt.Errorf("no schema with ref found at %s for %T: %w", key, value, ErrReplace)
}
func ErrNoSchema(key string) error {
return fmt.Errorf("no schema found at %s: %w", key, ErrReplace)
}
func ErrNotANumber(key string, err error) error {
return errors.Join(
ErrReplace,
fmt.Errorf("%s not a number: %w", key, err),
)
}
func ErrUnhandledParentRewrite(key string, value any) error {
return fmt.Errorf("unhandled parent schema rewrite %s: %T: %w", key, value, ErrReplace)
}
func ErrUnhandledParentType(key string, value any) error {
return fmt.Errorf("unhandled type for parent of %s: %T: %w", key, value, ErrReplace)
}
func ErrNoParent(key string, err error) error {
return errors.Join(
fmt.Errorf("can't get parent for %s: %w", key, err),
ErrReplace,
)
}
func ErrUnhandledContainerType(key string, value any) error {
return fmt.Errorf("unhandled container type at %s: %T: %w", key, value, ErrReplace)
}
func ErrCyclicChain(key string) error {
return fmt.Errorf("cannot resolve cyclic chain of pointers under %s: %w", key, ErrReplace)
}
func ErrInvalidPointerType(key string, value any, err error) error {
return fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T (%v): %w",
key, value, err, ErrReplace,
)
}

View file

@ -2,6 +2,7 @@ package replace
import (
"encoding/json"
"errors"
"fmt"
"net/url"
"os"
@ -13,7 +14,10 @@ import (
"github.com/go-openapi/spec"
)
const definitionsPath = "#/definitions"
const (
definitionsPath = "#/definitions"
allocMediumMap = 64
)
var debugLog = debug.GetLogger("analysis/flatten/replace", os.Getenv("SWAGGER_DEBUG") != "")
@ -44,7 +48,7 @@ func RewriteSchemaToRef(sp *spec.Swagger, key string, ref spec.Ref) error {
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:
return fmt.Errorf("no schema with ref found at %s for %T", key, value)
return ErrNoSchemaWithRef(key, value)
}
return nil
@ -69,7 +73,7 @@ func rewriteParentRef(sp *spec.Swagger, key string, ref spec.Ref) error {
case *spec.Responses:
statusCode, err := strconv.Atoi(entry)
if err != nil {
return fmt.Errorf("%s not a number: %w", key[1:], err)
return ErrNotANumber(key[1:], err)
}
resp := container.StatusCodeResponses[statusCode]
resp.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
@ -93,7 +97,7 @@ func rewriteParentRef(sp *spec.Swagger, key string, ref spec.Ref) error {
case []spec.Parameter:
idx, err := strconv.Atoi(entry)
if err != nil {
return fmt.Errorf("%s not a number: %w", key[1:], err)
return ErrNotANumber(key[1:], err)
}
param := container[idx]
param.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
@ -108,7 +112,7 @@ func rewriteParentRef(sp *spec.Swagger, key string, ref spec.Ref) error {
case []spec.Schema:
idx, err := strconv.Atoi(entry)
if err != nil {
return fmt.Errorf("%s not a number: %w", key[1:], err)
return ErrNotANumber(key[1:], err)
}
container[idx] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
@ -116,7 +120,7 @@ func rewriteParentRef(sp *spec.Swagger, key string, ref spec.Ref) error {
// NOTE: this is necessarily an array - otherwise, the parent would be *Schema
idx, err := strconv.Atoi(entry)
if err != nil {
return fmt.Errorf("%s not a number: %w", key[1:], err)
return ErrNotANumber(key[1:], err)
}
container.Schemas[idx] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
@ -129,7 +133,7 @@ func rewriteParentRef(sp *spec.Swagger, key string, ref spec.Ref) error {
// NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema
default:
return fmt.Errorf("unhandled parent schema rewrite %s (%T)", key, pvalue)
return ErrUnhandledParentRewrite(key, pvalue)
}
return nil
@ -141,7 +145,7 @@ func getPointerFromKey(sp interface{}, key string) (string, interface{}, error)
case *spec.Schema:
case *spec.Swagger:
default:
panic("unexpected type used in getPointerFromKey")
panic(ErrUnexpectedType)
}
if key == "#/" {
return "", sp, nil
@ -150,14 +154,14 @@ func getPointerFromKey(sp interface{}, key string) (string, interface{}, error)
pth, _ := url.PathUnescape(key[1:])
ptr, err := jsonpointer.New(pth)
if err != nil {
return "", nil, err
return "", nil, errors.Join(err, ErrReplace)
}
value, _, err := ptr.Get(sp)
if err != nil {
debugLog("error when getting key: %s with path: %s", key, pth)
return "", nil, err
return "", nil, errors.Join(err, ErrReplace)
}
return pth, value, nil
@ -169,7 +173,7 @@ func getParentFromKey(sp interface{}, key string) (string, string, interface{},
case *spec.Schema:
case *spec.Swagger:
default:
panic("unexpected type used in getPointerFromKey")
panic(ErrUnexpectedType)
}
// unescape chars in key, e.g. "{}" from path params
pth, _ := url.PathUnescape(key[1:])
@ -179,11 +183,11 @@ func getParentFromKey(sp interface{}, key string) (string, string, interface{},
pptr, err := jsonpointer.New(parent)
if err != nil {
return "", "", nil, err
return "", "", nil, errors.Join(err, ErrReplace)
}
pvalue, _, err := pptr.Get(sp)
if err != nil {
return "", "", nil, fmt.Errorf("can't get parent for %s: %w", parent, err)
return "", "", nil, ErrNoParent(parent, err)
}
return parent, entry, pvalue, nil
@ -195,7 +199,7 @@ func UpdateRef(sp interface{}, key string, ref spec.Ref) error {
case *spec.Schema:
case *spec.Swagger:
default:
panic("unexpected type used in getPointerFromKey")
panic(ErrUnexpectedType)
}
debugLog("updating ref for %s with %s", key, ref.String())
pth, value, err := getPointerFromKey(sp, key)
@ -218,7 +222,7 @@ func UpdateRef(sp interface{}, key string, ref spec.Ref) error {
debugLog("rewriting holder for %T", refable)
_, entry, pvalue, erp := getParentFromKey(sp, key)
if erp != nil {
return err
return erp
}
switch container := pvalue.(type) {
case spec.Definitions:
@ -230,7 +234,7 @@ func UpdateRef(sp interface{}, key string, ref spec.Ref) error {
case []spec.Schema:
idx, err := strconv.Atoi(entry)
if err != nil {
return fmt.Errorf("%s not a number: %w", pth, err)
return ErrNotANumber(pth, err)
}
container[idx] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
@ -238,7 +242,7 @@ func UpdateRef(sp interface{}, key string, ref spec.Ref) error {
// NOTE: this is necessarily an array - otherwise, the parent would be *Schema
idx, err := strconv.Atoi(entry)
if err != nil {
return fmt.Errorf("%s not a number: %w", pth, err)
return ErrNotANumber(pth, err)
}
container.Schemas[idx] = spec.Schema{SchemaProps: spec.SchemaProps{Ref: ref}}
@ -248,11 +252,11 @@ func UpdateRef(sp interface{}, key string, ref spec.Ref) error {
// NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema
default:
return fmt.Errorf("unhandled container type at %s: %T", key, value)
return ErrUnhandledContainerType(key, value)
}
default:
return fmt.Errorf("no schema with ref found at %s for %T", key, value)
return ErrNoSchemaWithRef(key, value)
}
return nil
@ -272,8 +276,9 @@ func UpdateRefWithSchema(sp *spec.Swagger, key string, sch *spec.Schema) error {
case spec.Schema:
_, entry, pvalue, erp := getParentFromKey(sp, key)
if erp != nil {
return err
return erp
}
switch container := pvalue.(type) {
case spec.Definitions:
container[entry] = *sch
@ -284,7 +289,7 @@ func UpdateRefWithSchema(sp *spec.Swagger, key string, sch *spec.Schema) error {
case []spec.Schema:
idx, err := strconv.Atoi(entry)
if err != nil {
return fmt.Errorf("%s not a number: %w", pth, err)
return ErrNotANumber(pth, err)
}
container[idx] = *sch
@ -292,7 +297,7 @@ func UpdateRefWithSchema(sp *spec.Swagger, key string, sch *spec.Schema) error {
// NOTE: this is necessarily an array - otherwise, the parent would be *Schema
idx, err := strconv.Atoi(entry)
if err != nil {
return fmt.Errorf("%s not a number: %w", pth, err)
return ErrNotANumber(pth, err)
}
container.Schemas[idx] = *sch
@ -302,7 +307,7 @@ func UpdateRefWithSchema(sp *spec.Swagger, key string, sch *spec.Schema) error {
// NOTE: can't have case *spec.SchemaOrBool = parent in this case is *Schema
default:
return fmt.Errorf("unhandled type for parent of [%s]: %T", key, value)
return ErrUnhandledParentType(key, value)
}
case *spec.SchemaOrArray:
*refable.Schema = *sch
@ -310,7 +315,7 @@ func UpdateRefWithSchema(sp *spec.Swagger, key string, sch *spec.Schema) error {
case *spec.SchemaOrBool:
*refable.Schema = *sch
default:
return fmt.Errorf("no schema with ref found at %s for %T", key, value)
return ErrNoSchemaWithRef(key, value)
}
return nil
@ -336,8 +341,8 @@ func DeepestRef(sp *spec.Swagger, opts *spec.ExpandOptions, ref spec.Ref) (*Deep
}
currentRef := ref
visited := make(map[string]bool, 64)
warnings := make([]string, 0, 2)
visited := make(map[string]bool, allocMediumMap)
warnings := make([]string, 0)
DOWNREF:
for currentRef.String() != "" {
@ -347,8 +352,7 @@ DOWNREF:
}
if _, beenThere := visited[currentRef.String()]; beenThere {
return nil,
fmt.Errorf("cannot resolve cyclic chain of pointers under %s", currentRef.String())
return nil, ErrCyclicChain(currentRef.String())
}
visited[currentRef.String()] = true
@ -390,10 +394,7 @@ DOWNREF:
err := asSchema.UnmarshalJSON(asJSON)
if err != nil {
return nil,
fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T (%v)",
currentRef.String(), value, err,
)
return nil, ErrInvalidPointerType(currentRef.String(), value, err)
}
warnings = append(warnings, fmt.Sprintf("found $ref %q (response) interpreted as schema", currentRef.String()))
@ -408,10 +409,7 @@ DOWNREF:
asJSON, _ := refable.MarshalJSON()
var asSchema spec.Schema
if err := asSchema.UnmarshalJSON(asJSON); err != nil {
return nil,
fmt.Errorf("invalid type for resolved JSON pointer %s. Expected a schema a, got: %T (%v)",
currentRef.String(), value, err,
)
return nil, ErrInvalidPointerType(currentRef.String(), value, err)
}
warnings = append(warnings, fmt.Sprintf("found $ref %q (parameter) interpreted as schema", currentRef.String()))
@ -430,10 +428,7 @@ DOWNREF:
asJSON, _ := json.Marshal(refable)
var asSchema spec.Schema
if err := asSchema.UnmarshalJSON(asJSON); err != nil {
return nil,
fmt.Errorf("unhandled type to resolve JSON pointer %s. Expected a Schema, got: %T (%v)",
currentRef.String(), value, err,
)
return nil, ErrInvalidPointerType(currentRef.String(), value, err)
}
warnings = append(warnings, fmt.Sprintf("found $ref %q (%T) interpreted as schema", currentRef.String(), refable))
@ -451,7 +446,7 @@ DOWNREF:
}
if sch == nil {
return nil, fmt.Errorf("no schema found at %s", currentRef.String())
return nil, ErrNoSchema(currentRef.String())
}
return &DeepestRefResult{Ref: currentRef, Schema: sch, Warnings: warnings}, nil

View file

@ -4,9 +4,11 @@ package schutils
import (
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
const allocLargeMap = 150
// Save registers a schema as an entry in spec #/definitions
func Save(sp *spec.Swagger, name string, schema *spec.Schema) {
if schema == nil {
@ -14,7 +16,7 @@ func Save(sp *spec.Swagger, name string, schema *spec.Schema) {
}
if sp.Definitions == nil {
sp.Definitions = make(map[string]spec.Schema, 150)
sp.Definitions = make(map[string]spec.Schema, allocLargeMap)
}
sp.Definitions[name] = *schema
@ -23,7 +25,7 @@ func Save(sp *spec.Swagger, name string, schema *spec.Schema) {
// Clone deep-clones a schema
func Clone(schema *spec.Schema) *spec.Schema {
var sch spec.Schema
_ = swag.FromDynamicJSON(schema, &sch)
_ = jsonutils.FromDynamicJSON(schema, &sch)
return &sch
}

View file

@ -86,22 +86,6 @@ func (s SplitKey) DefinitionName() string {
return s[1]
}
func (s SplitKey) isKeyName(i int) bool {
if i <= 0 {
return false
}
count := 0
for idx := i - 1; idx > 0; idx-- {
if s[idx] != "properties" {
break
}
count++
}
return count%2 != 0
}
// PartAdder know how to construct the components of a new name
type PartAdder func(string) []string
@ -179,7 +163,8 @@ func (s SplitKey) ResponseName() string {
// PathItemRef constructs a $ref object from a split key of the form /{path}/{method}
func (s SplitKey) PathItemRef() spec.Ref {
if len(s) < 3 {
const minValidPathItems = 3
if len(s) < minValidPathItems {
return spec.Ref{}
}
@ -199,3 +184,19 @@ func (s SplitKey) PathRef() spec.Ref {
return spec.MustCreateRef("#" + path.Join("/", paths, jsonpointer.Escape(s[1])))
}
func (s SplitKey) isKeyName(i int) bool {
if i <= 0 {
return false
}
count := 0
for idx := i - 1; idx > 0; idx-- {
if s[idx] != "properties" {
break
}
count++
}
return count%2 != 0
}

View file

@ -391,7 +391,7 @@ func mergeInfo(primary *spec.Info, m *spec.Info) []string {
}
if primary.Title == "" {
primary.Description = m.Description
primary.Title = m.Title
}
if primary.TermsOfService == "" {
@ -474,23 +474,23 @@ func initPrimary(primary *spec.Swagger) {
}
if primary.Security == nil {
primary.Security = make([]map[string][]string, 0, 10)
primary.Security = make([]map[string][]string, 0, allocSmallMap)
}
if primary.Produces == nil {
primary.Produces = make([]string, 0, 10)
primary.Produces = make([]string, 0, allocSmallMap)
}
if primary.Consumes == nil {
primary.Consumes = make([]string, 0, 10)
primary.Consumes = make([]string, 0, allocSmallMap)
}
if primary.Tags == nil {
primary.Tags = make([]spec.Tag, 0, 10)
primary.Tags = make([]spec.Tag, 0, allocSmallMap)
}
if primary.Schemes == nil {
primary.Schemes = make([]string, 0, 10)
primary.Schemes = make([]string, 0, allocSmallMap)
}
if primary.Paths == nil {

View file

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

View file

@ -16,7 +16,7 @@ linters:
- godox
- gosmopolitan
- inamedparam
- intrange # disabled while < go1.22
#- intrange # disabled while < go1.22
- ireturn
- lll
- musttag

View file

@ -71,12 +71,12 @@ func NotFound(message string, args ...interface{}) Error {
if message == "" {
message = "Not found"
}
return New(http.StatusNotFound, fmt.Sprintf(message, args...))
return New(http.StatusNotFound, message, args...)
}
// NotImplemented creates a new not implemented error
func NotImplemented(message string) Error {
return New(http.StatusNotImplemented, message)
return New(http.StatusNotImplemented, "%s", message)
}
// MethodNotAllowedError represents an error for when the path matches but the method doesn't
@ -179,7 +179,7 @@ func ServeError(rw http.ResponseWriter, r *http.Request, err error) {
default:
rw.WriteHeader(http.StatusInternalServerError)
if r == nil || r.Method != http.MethodHead {
_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, err.Error())))
_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "%v", err)))
}
}
}

View file

@ -16,13 +16,16 @@ linters:
- godox
- gosmopolitan
- inamedparam
#- intrange # disabled while < go1.22
- ireturn
- lll
- musttag
- nestif
- nlreturn
- nonamedreturns
- noinlineerr
- paralleltest
- recvcheck
- testpackage
- thelper
- tparallel
@ -31,6 +34,7 @@ linters:
- whitespace
- wrapcheck
- wsl
- wsl_v5
settings:
dupl:
threshold: 200
@ -60,3 +64,12 @@ formatters:
- third_party$
- builtin$
- examples$
issues:
# Maximum issues count per one linter.
# Set to 0 to disable.
# Default: 50
max-issues-per-linter: 0
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 0

View file

@ -13,7 +13,14 @@ Completed YES
Tested YES
## References
http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
<https://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07>
also known as [RFC6901](https://www.rfc-editor.org/rfc/rfc6901)
### Note
The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented.
That is because our implementation of the JSON pointer only supports explicit references to array elements: the provision in the spec
to resolve non-existent members as "the last element in the array", using the special trailing character "-".

View file

@ -33,7 +33,7 @@ import (
"strconv"
"strings"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonname"
)
const (
@ -41,8 +41,10 @@ const (
pointerSeparator = `/`
)
var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
var (
jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
)
// JSONPointable is an interface for structs to implement when they need to customize the
// json pointer process
@ -56,23 +58,87 @@ type JSONSetable interface {
JSONSet(string, any) error
}
// New creates a new json pointer for the given string
func New(jsonPointerString string) (Pointer, error) {
var p Pointer
err := p.parse(jsonPointerString)
return p, err
}
// Pointer the json pointer reprsentation
// Pointer is a representation of a json pointer
type Pointer struct {
referenceTokens []string
}
// New creates a new json pointer for the given string
func New(jsonPointerString string) (Pointer, error) {
var p Pointer
err := p.parse(jsonPointerString)
return p, err
}
// Get uses the pointer to retrieve a value from a JSON document
func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
return p.get(document, jsonname.DefaultJSONNameProvider)
}
// Set uses the pointer to set a value from a JSON document
func (p *Pointer) Set(document any, value any) (any, error) {
return document, p.set(document, value, jsonname.DefaultJSONNameProvider)
}
// DecodedTokens returns the decoded tokens of this JSON pointer
func (p *Pointer) DecodedTokens() []string {
result := make([]string, 0, len(p.referenceTokens))
for _, t := range p.referenceTokens {
result = append(result, Unescape(t))
}
return result
}
// IsEmpty returns true if this is an empty json pointer
// this indicates that it points to the root document
func (p *Pointer) IsEmpty() bool {
return len(p.referenceTokens) == 0
}
// Pointer to string representation function
func (p *Pointer) String() string {
if len(p.referenceTokens) == 0 {
return emptyPointer
}
return pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
}
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: %w", tk, ErrPointer)
}
default:
return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
}
}
return offset, nil
}
// "Constructor", parses the given string JSON pointer
func (p *Pointer) parse(jsonPointerString string) error {
var err error
if jsonPointerString != emptyPointer {
@ -87,24 +153,134 @@ func (p *Pointer) parse(jsonPointerString string) error {
return err
}
// Get uses the pointer to retrieve a value from a JSON document
func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
return p.get(document, swag.DefaultJSONNameProvider)
func (p *Pointer) get(node any, nameProvider *jsonname.NameProvider) (any, reflect.Kind, error) {
if nameProvider == nil {
nameProvider = jsonname.DefaultJSONNameProvider
}
kind := reflect.Invalid
// Full document when empty
if len(p.referenceTokens) == 0 {
return node, kind, nil
}
for _, token := range p.referenceTokens {
decodedToken := Unescape(token)
r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
if err != nil {
return nil, knd, err
}
node = r
}
rValue := reflect.ValueOf(node)
kind = rValue.Kind()
return node, kind, nil
}
// Set uses the pointer to set a value from a JSON document
func (p *Pointer) Set(document any, value any) (any, error) {
return document, p.set(document, value, swag.DefaultJSONNameProvider)
}
func (p *Pointer) set(node, data any, nameProvider *jsonname.NameProvider) error {
knd := reflect.ValueOf(node).Kind()
// GetForToken gets a value for a json pointer token 1 level deep
func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
}
if knd != reflect.Pointer && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
return errors.Join(
ErrUnsupportedValueType,
ErrPointer,
)
}
// SetForToken gets a value for a json pointer token 1 level deep
func SetForToken(document any, decodedToken string, value any) (any, error) {
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
if nameProvider == nil {
nameProvider = jsonname.DefaultJSONNameProvider
}
// Full document when empty
if len(p.referenceTokens) == 0 {
return nil
}
lastI := len(p.referenceTokens) - 1
for i, token := range p.referenceTokens {
isLastToken := i == lastI
decodedToken := Unescape(token)
if isLastToken {
return setSingleImpl(node, data, decodedToken, nameProvider)
}
// Check for nil during traversal
if isNil(node) {
return fmt.Errorf("cannot traverse through nil value at %q: %w", decodedToken, ErrPointer)
}
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
if err != nil {
return err
}
fld := reflect.ValueOf(r)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Pointer {
node = fld.Addr().Interface()
continue
}
node = r
continue
}
switch kind { //nolint:exhaustive
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
}
fld := rValue.FieldByName(nm)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Pointer {
node = fld.Addr().Interface()
continue
}
node = fld.Interface()
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if !mv.IsValid() {
return fmt.Errorf("object has no key %q: %w", decodedToken, ErrPointer)
}
if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Pointer {
node = mv.Addr().Interface()
continue
}
node = mv.Interface()
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength, tokenIndex, ErrPointer)
}
elem := rValue.Index(tokenIndex)
if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Pointer {
node = elem.Addr().Interface()
continue
}
node = elem.Interface()
default:
return fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
}
}
return nil
}
func isNil(input any) bool {
@ -114,14 +290,24 @@ func isNil(input any) bool {
kind := reflect.TypeOf(input).Kind()
switch kind { //nolint:exhaustive
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
case reflect.Pointer, 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) {
// GetForToken gets a value for a json pointer token 1 level deep
func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
return getSingleImpl(document, decodedToken, jsonname.DefaultJSONNameProvider)
}
// SetForToken gets a value for a json pointer token 1 level deep
func SetForToken(document any, decodedToken string, value any) (any, error) {
return document, setSingleImpl(document, value, decodedToken, jsonname.DefaultJSONNameProvider)
}
func getSingleImpl(node any, decodedToken string, nameProvider *jsonname.NameProvider) (any, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if isNil(node) {
@ -173,10 +359,9 @@ func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvide
default:
return nil, kind, fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
}
}
func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameProvider) error {
func setSingleImpl(node, data any, decodedToken string, nameProvider *jsonname.NameProvider) error {
rValue := reflect.Indirect(reflect.ValueOf(node))
// Check for nil to prevent panic when calling rValue.Type()
@ -229,197 +414,6 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameP
default:
return fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
}
}
func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
if nameProvider == nil {
nameProvider = swag.DefaultJSONNameProvider
}
kind := reflect.Invalid
// Full document when empty
if len(p.referenceTokens) == 0 {
return node, kind, nil
}
for _, token := range p.referenceTokens {
decodedToken := Unescape(token)
r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
if err != nil {
return nil, knd, err
}
node = r
}
rValue := reflect.ValueOf(node)
kind = rValue.Kind()
return node, kind, nil
}
func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error {
knd := reflect.ValueOf(node).Kind()
if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
return errors.Join(
ErrUnsupportedValueType,
ErrPointer,
)
}
if nameProvider == nil {
nameProvider = swag.DefaultJSONNameProvider
}
// Full document when empty
if len(p.referenceTokens) == 0 {
return nil
}
lastI := len(p.referenceTokens) - 1
for i, token := range p.referenceTokens {
isLastToken := i == lastI
decodedToken := Unescape(token)
if isLastToken {
return setSingleImpl(node, data, decodedToken, nameProvider)
}
// Check for nil during traversal
if isNil(node) {
return fmt.Errorf("cannot traverse through nil value at %q: %w", decodedToken, ErrPointer)
}
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
if err != nil {
return err
}
fld := reflect.ValueOf(r)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
node = fld.Addr().Interface()
continue
}
node = r
continue
}
switch kind { //nolint:exhaustive
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
}
fld := rValue.FieldByName(nm)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
node = fld.Addr().Interface()
continue
}
node = fld.Interface()
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if !mv.IsValid() {
return fmt.Errorf("object has no key %q: %w", decodedToken, ErrPointer)
}
if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
node = mv.Addr().Interface()
continue
}
node = mv.Interface()
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength, tokenIndex, ErrPointer)
}
elem := rValue.Index(tokenIndex)
if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
node = elem.Addr().Interface()
continue
}
node = elem.Interface()
default:
return fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
}
}
return nil
}
// DecodedTokens returns the decoded tokens
func (p *Pointer) DecodedTokens() []string {
result := make([]string, 0, len(p.referenceTokens))
for _, t := range p.referenceTokens {
result = append(result, Unescape(t))
}
return result
}
// IsEmpty returns true if this is an empty json pointer
// this indicates that it points to the root document
func (p *Pointer) IsEmpty() bool {
return len(p.referenceTokens) == 0
}
// Pointer to string representation function
func (p *Pointer) String() string {
if len(p.referenceTokens) == 0 {
return emptyPointer
}
pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
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: %w", tk, ErrPointer)
}
default:
return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
}
}
return offset, nil
}
func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
@ -525,16 +519,17 @@ const (
decRefTok1 = `/`
)
var (
encRefTokReplacer = strings.NewReplacer(encRefTok1, decRefTok1, encRefTok0, decRefTok0)
decRefTokReplacer = strings.NewReplacer(decRefTok1, encRefTok1, decRefTok0, encRefTok0)
)
// Unescape unescapes a json pointer reference token string to the original representation
func Unescape(token string) string {
step1 := strings.ReplaceAll(token, encRefTok1, decRefTok1)
step2 := strings.ReplaceAll(step1, encRefTok0, decRefTok0)
return step2
return encRefTokReplacer.Replace(token)
}
// Escape escapes a pointer reference token string
func Escape(token string) string {
step1 := strings.ReplaceAll(token, decRefTok0, encRefTok0)
step2 := strings.ReplaceAll(step1, decRefTok1, encRefTok1)
return step2
return decRefTokReplacer.Replace(token)
}

View file

@ -1,61 +1,75 @@
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
version: "2"
linters:
enable-all: true
default: all
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
- cyclop
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- errorlint
- exhaustruct
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase
- funlen
- gochecknoglobals
- gochecknoinits
- gocognit
- godot
- godox
- gosmopolitan
- inamedparam
#- intrange # disabled while < go1.22
- ireturn
- lll
- musttag
- nestif
- nlreturn
- nonamedreturns
- noinlineerr
- paralleltest
- recvcheck
- testpackage
- thelper
- tparallel
- unparam
- varnamelen
- whitespace
- wrapcheck
- wsl
- wsl_v5
settings:
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
gocyclo:
min-complexity: 45
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
# Maximum issues count per one linter.
# Set to 0 to disable.
# Default: 50
max-issues-per-linter: 0
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 0

View file

@ -38,24 +38,7 @@ const (
fragmentRune = `#`
)
// New creates a new reference for the given string
func New(jsonReferenceString string) (Ref, error) {
var r Ref
err := r.parse(jsonReferenceString)
return r, err
}
// MustCreateRef parses the ref string and panics when it's invalid.
// Use the New method for a version that returns an error
func MustCreateRef(ref string) Ref {
r, err := New(ref)
if err != nil {
panic(err)
}
return r
}
var ErrChildURL = errors.New("child url is nil")
// Ref represents a json reference object
type Ref struct {
@ -69,6 +52,24 @@ type Ref struct {
HasFullFilePath bool
}
// New creates a new reference for the given string
func New(jsonReferenceString string) (Ref, error) {
var r Ref
err := r.parse(jsonReferenceString)
return r, err
}
// MustCreateRef parses the ref string and panics when it's invalid.
// Use the New method for a version that returns an error
func MustCreateRef(ref string) Ref {
r, err := New(ref)
if err != nil {
panic(err)
}
return r
}
// GetURL gets the URL for this reference
func (r *Ref) GetURL() *url.URL {
return r.referenceURL
@ -81,7 +82,6 @@ func (r *Ref) GetPointer() *jsonpointer.Pointer {
// String returns the best version of the url for this reference
func (r *Ref) String() string {
if r.referenceURL != nil {
return r.referenceURL.String()
}
@ -106,9 +106,27 @@ func (r *Ref) IsCanonical() bool {
return (r.HasFileScheme && r.HasFullFilePath) || (!r.HasFileScheme && r.HasFullURL)
}
// Inherits creates a new reference from a parent and a child
// If the child cannot inherit from the parent, an error is returned
func (r *Ref) Inherits(child Ref) (*Ref, error) {
childURL := child.GetURL()
parentURL := r.GetURL()
if childURL == nil {
return nil, ErrChildURL
}
if parentURL == nil {
return &child, nil
}
ref, err := New(parentURL.ResolveReference(childURL).String())
if err != nil {
return nil, err
}
return &ref, nil
}
// "Constructor", parses the given string JSON reference
func (r *Ref) parse(jsonReferenceString string) error {
parsed, err := url.Parse(jsonReferenceString)
if err != nil {
return err
@ -137,22 +155,3 @@ func (r *Ref) parse(jsonReferenceString string) error {
return nil
}
// Inherits creates a new reference from a parent and a child
// If the child cannot inherit from the parent, an error is returned
func (r *Ref) Inherits(child Ref) (*Ref, error) {
childURL := child.GetURL()
parentURL := r.GetURL()
if childURL == nil {
return nil, errors.New("child url is nil")
}
if parentURL == nil {
return &child, nil
}
ref, err := New(parentURL.ResolveReference(childURL).String())
if err != nil {
return nil, err
}
return &ref, nil
}

View file

@ -1,61 +1,75 @@
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
version: "2"
linters:
enable-all: true
default: all
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
- cyclop
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- errorlint
- exhaustruct
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase
- funlen
- gochecknoglobals
- gochecknoinits
- gocognit
- godot
- godox
- gosmopolitan
- inamedparam
#- intrange # disabled while < go1.22
- ireturn
- lll
- musttag
- nestif
- nlreturn
- nonamedreturns
- noinlineerr
- paralleltest
- recvcheck
- testpackage
- thelper
- tparallel
- unparam
- varnamelen
- whitespace
- wrapcheck
- wsl
- wsl_v5
settings:
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
gocyclo:
min-complexity: 45
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
# Maximum issues count per one linter.
# Set to 0 to disable.
# Default: 50
max-issues-per-linter: 0
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 0

View file

@ -3,4 +3,26 @@
[![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)
Loading of OAI specification documents from local or remote locations. Supports JSON and YAML documents.
Loading of OAI v2 API specification documents from local or remote locations. Supports JSON and YAML documents.
Primary usage:
```go
import (
"github.com/go-openapi/loads"
)
...
// loads a YAML spec from a http file
doc, err := loads.Spec(ts.URL)
...
// retrieves the object model for the API specification
spec := doc.Spec()
...
```
See also the provided [examples](https://pkg.go.dev/github.com/go-openapi/loads#pkg-examples).

View file

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

15
vendor/github.com/go-openapi/loads/errors.go generated vendored Normal file
View file

@ -0,0 +1,15 @@
package loads
type loaderError string
func (e loaderError) Error() string {
return string(e)
}
const (
// ErrLoads is an error returned by the loads package
ErrLoads loaderError = "loaderrs error"
// ErrNoLoader indicates that no configured loader matched the input
ErrNoLoader loaderError = "no loader matched"
)

View file

@ -4,9 +4,10 @@ import (
"encoding/json"
"errors"
"net/url"
"slices"
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/loading"
)
var (
@ -30,8 +31,8 @@ func init() {
loaders = jsonLoader.WithHead(&loader{
DocLoaderWithMatch: DocLoaderWithMatch{
Match: swag.YAMLMatcher,
Fn: swag.YAMLDoc,
Match: loading.YAMLMatcher,
Fn: loading.YAMLDoc,
},
})
@ -40,7 +41,7 @@ func init() {
}
// DocLoader represents a doc loader type
type DocLoader func(string) (json.RawMessage, error)
type DocLoader func(string, ...loading.Option) (json.RawMessage, error)
// DocMatcher represents a predicate to check if a loader matches
type DocMatcher func(string) bool
@ -61,6 +62,9 @@ func NewDocLoaderWithMatch(fn DocLoader, matcher DocMatcher) DocLoaderWithMatch
type loader struct {
DocLoaderWithMatch
loadingOptions []loading.Option
Next *loader
}
@ -83,17 +87,17 @@ func (l *loader) WithNext(next *loader) *loader {
func (l *loader) Load(path string) (json.RawMessage, error) {
_, erp := url.Parse(path)
if erp != nil {
return nil, erp
return nil, errors.Join(erp, ErrLoads)
}
lastErr := errors.New("no loader matched") // default error if no match was found
var lastErr error = ErrNoLoader // default error if no match was found
for ldr := l; ldr != nil; ldr = ldr.Next {
if ldr.Match != nil && !ldr.Match(path) {
continue
}
// try then move to next one if there is an error
b, err := ldr.Fn(path)
b, err := ldr.Fn(path, l.loadingOptions...)
if err == nil {
return b, nil
}
@ -101,14 +105,29 @@ func (l *loader) Load(path string) (json.RawMessage, error) {
lastErr = err
}
return nil, lastErr
return nil, errors.Join(lastErr, ErrLoads)
}
// JSONDoc loads a json document from either a file or a remote url
func JSONDoc(path string) (json.RawMessage, error) {
data, err := swag.LoadFromFileOrHTTP(path)
func (l *loader) clone() *loader {
if l == nil {
return nil
}
return &loader{
DocLoaderWithMatch: l.DocLoaderWithMatch,
loadingOptions: slices.Clone(l.loadingOptions),
Next: l.Next.clone(),
}
}
// JSONDoc loads a json document from either a file or a remote url.
//
// See [loading.Option] for available options (e.g. configuring authentifaction,
// headers or using embedded file system resources).
func JSONDoc(path string, opts ...loading.Option) (json.RawMessage, error) {
data, err := loading.LoadFromFileOrHTTP(path, opts...)
if err != nil {
return nil, err
return nil, errors.Join(err, ErrLoads)
}
return json.RawMessage(data), nil
}

View file

@ -1,7 +1,10 @@
package loads
import "github.com/go-openapi/swag/loading"
type options struct {
loader *loader
loader *loader
loadingOptions []loading.Option
}
func defaultOptions() *options {
@ -16,7 +19,10 @@ func loaderFromOptions(options []LoaderOption) *loader {
apply(opts)
}
return opts.loader
l := opts.loader.clone()
l.loadingOptions = opts.loadingOptions
return l
}
// LoaderOption allows to fine-tune the spec loader behavior
@ -59,3 +65,10 @@ func WithDocLoaderMatches(l ...DocLoaderWithMatch) LoaderOption {
opt.loader = final
}
}
// WithLoadingOptions adds some [loading.Option] to be added when calling a registered loader.
func WithLoadingOptions(loadingOptions ...loading.Option) LoaderOption {
return func(opt *options) {
opt.loadingOptions = loadingOptions
}
}

View file

@ -18,16 +18,18 @@ import (
"bytes"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"maps"
"github.com/go-openapi/analysis"
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/yamlutils"
)
func init() {
gob.Register(map[string]interface{}{})
gob.Register([]interface{}{})
gob.Register(map[string]any{})
gob.Register([]any{})
}
// Document represents a swagger spec document
@ -42,14 +44,21 @@ type Document struct {
raw json.RawMessage
}
// JSONSpec loads a spec from a json document
func JSONSpec(path string, options ...LoaderOption) (*Document, error) {
data, err := JSONDoc(path)
// JSONSpec loads a spec from a json document, using the [JSONDoc] loader.
//
// A set of [loading.Option] may be passed to this loader using [WithLoadingOptions].
func JSONSpec(path string, opts ...LoaderOption) (*Document, error) {
var o options
for _, apply := range opts {
apply(&o)
}
data, err := JSONDoc(path, o.loadingOptions...)
if err != nil {
return nil, err
}
// convert to json
doc, err := Analyzed(data, "", options...)
doc, err := Analyzed(data, "", opts...)
if err != nil {
return nil, err
}
@ -59,8 +68,8 @@ func JSONSpec(path string, options ...LoaderOption) (*Document, error) {
return doc, nil
}
// Embedded returns a Document based on embedded specs. No analysis is required
func Embedded(orig, flat json.RawMessage, options ...LoaderOption) (*Document, error) {
// Embedded returns a Document based on embedded specs (i.e. as a raw [json.RawMessage]). No analysis is required
func Embedded(orig, flat json.RawMessage, opts ...LoaderOption) (*Document, error) {
var origSpec, flatSpec spec.Swagger
if err := json.Unmarshal(orig, &origSpec); err != nil {
return nil, err
@ -72,20 +81,22 @@ func Embedded(orig, flat json.RawMessage, options ...LoaderOption) (*Document, e
raw: orig,
origSpec: &origSpec,
spec: &flatSpec,
pathLoader: loaderFromOptions(options),
pathLoader: loaderFromOptions(opts),
}, nil
}
// Spec loads a new spec document from a local or remote path
func Spec(path string, options ...LoaderOption) (*Document, error) {
ldr := loaderFromOptions(options)
// Spec loads a new spec document from a local or remote path.
//
// By default it uses a JSON or YAML loader, with auto-detection based on the resource extension.
func Spec(path string, opts ...LoaderOption) (*Document, error) {
ldr := loaderFromOptions(opts)
b, err := ldr.Load(path)
if err != nil {
return nil, err
}
document, err := Analyzed(b, "", options...)
document, err := Analyzed(b, "", opts...)
if err != nil {
return nil, err
}
@ -102,7 +113,7 @@ func Analyzed(data json.RawMessage, version string, options ...LoaderOption) (*D
version = "2.0"
}
if version != "2.0" {
return nil, fmt.Errorf("spec version %q is not supported", version)
return nil, fmt.Errorf("spec version %q is not supported: %w", version, ErrLoads)
}
raw, err := trimData(data) // trim blanks, then convert yaml docs into json
@ -112,12 +123,12 @@ func Analyzed(data json.RawMessage, version string, options ...LoaderOption) (*D
swspec := new(spec.Swagger)
if err = json.Unmarshal(raw, swspec); err != nil {
return nil, err
return nil, errors.Join(err, ErrLoads)
}
origsqspec, err := cloneSpec(swspec)
if err != nil {
return nil, err
return nil, errors.Join(err, ErrLoads)
}
d := &Document{
@ -143,20 +154,20 @@ func trimData(in json.RawMessage) (json.RawMessage, error) {
}
// assume yaml doc: convert it to json
yml, err := swag.BytesToYAMLDoc(trimmed)
yml, err := yamlutils.BytesToYAMLDoc(trimmed)
if err != nil {
return nil, fmt.Errorf("analyzed: %v", err)
return nil, fmt.Errorf("analyzed: %v: %w", err, ErrLoads)
}
d, err := swag.YAMLToJSON(yml)
d, err := yamlutils.YAMLToJSON(yml)
if err != nil {
return nil, fmt.Errorf("analyzed: %v", err)
return nil, fmt.Errorf("analyzed: %v: %w", err, ErrLoads)
}
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 expanded [Document]
func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
swspec := new(spec.Swagger)
if err := json.Unmarshal(d.raw, swspec); err != nil {
@ -202,20 +213,23 @@ func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
// BasePath the base path for the API specified by this spec
func (d *Document) BasePath() string {
if d.spec == nil {
return ""
}
return d.spec.BasePath
}
// Version returns the version of this spec
// Version returns the OpenAPI version of this spec (e.g. 2.0)
func (d *Document) Version() string {
return d.spec.Swagger
}
// Schema returns the swagger 2.0 schema
// Schema returns the swagger 2.0 meta-schema
func (d *Document) Schema() *spec.Schema {
return d.schema
}
// Spec returns the swagger spec object model
// Spec returns the swagger object model for this API specification
func (d *Document) Spec() *spec.Swagger {
return d.spec
}
@ -235,14 +249,11 @@ func (d *Document) OrigSpec() *spec.Swagger {
return d.origSpec
}
// ResetDefinitions gives a shallow copy with the models reset to the original spec
// ResetDefinitions yields a shallow copy with the models reset to the original spec
func (d *Document) ResetDefinitions() *Document {
defs := make(map[string]spec.Schema, len(d.origSpec.Definitions))
for k, v := range d.origSpec.Definitions {
defs[k] = v
}
d.spec.Definitions = make(map[string]spec.Schema, len(d.origSpec.Definitions))
maps.Copy(d.spec.Definitions, d.origSpec.Definitions)
d.spec.Definitions = defs
return d
}
@ -271,5 +282,6 @@ func cloneSpec(src *spec.Swagger) (*spec.Swagger, error) {
if err := gob.NewDecoder(&b).Decode(&dst); err != nil {
return nil, err
}
return &dst, nil
}

View file

@ -1,62 +1,78 @@
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
version: "2"
linters:
enable-all: true
default: all
disable:
- nilerr # nilerr crashes on this repo
- 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
- depguard
- err113 # disabled temporarily: there are just too many issues to address
- errchkjson
- errorlint
- exhaustruct
- forcetypeassert
- funlen
- gochecknoglobals
- gochecknoinits
- gocognit
- godot
- godox
- gomoddirectives # moved to mono-repo, multi-modules, so replace directives are needed
- gosmopolitan
- inamedparam
#- intrange # disabled while < go1.22
- ireturn
- lll
- musttag
- nestif
- nilerr # nilerr crashes on this repo
- nlreturn
- noinlineerr
- nonamedreturns
- paralleltest
- recvcheck
- testpackage
- thelper
- tparallel
- unparam
- varnamelen
- whitespace
- wrapcheck
- wsl
- wsl_v5
settings:
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
gocyclo:
min-complexity: 45
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
# Maximum issues count per one linter.
# Set to 0 to disable.
# Default: 50
max-issues-per-linter: 0
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 0

View file

@ -8,3 +8,32 @@
# go OpenAPI toolkit runtime
The runtime component for use in code generation or as untyped usage.
## Release notes
### v0.29.0 [draft, unpublished]
**New with this release**:
* upgraded to `go1.24` and modernized the code base accordingly
* updated all dependencies, and removed an noticable indirect dependency (e.g. `mailru/easyjson`)
* **breaking change** no longer imports `opentracing-go` (#365).
* the `WithOpentracing()` method now returns an opentelemetry transport
* for users who can't transition to opentelemetry, the previous behavior
of `WithOpentracing` delivering an opentracing transport is provided by a separate
module `github.com/go-openapi/runtime/client-middleware/opentracing`.
* removed direct dependency to `gopkg.in/yaml.v3`, in favor of `go.yaml.in/yaml/v3` (an indirect
test dependency to the older package is still around)
* technically, the repo has evolved to a mono-repo, multiple modules structures (2 go modules
published), with CI adapted accordingly
**What coming next?**
Moving forward, we want to :
* [ ] continue narrowing down the scope of dependencies:
* yaml support in an independent module
* introduce more up-to-date support for opentelemetry as a separate module that evolves
independently from the main package (to avoid breaking changes, the existing API
will remain maintained, but evolve at a slower pace than opentelemetry).
* [ ] fix a few known issues with some file upload requests (e.g. #286)

View file

@ -22,7 +22,7 @@ import (
"io"
"reflect"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
func defaultCloser() error { return nil }
@ -206,7 +206,7 @@ func ByteStreamProducer(opts ...byteStreamOpt) Producer {
return err
case t.Kind() == reflect.Struct || t.Kind() == reflect.Slice:
b, err := swag.WriteJSON(data)
b, err := jsonutils.WriteJSON(data)
if err != nil {
return err
}

View file

@ -11,8 +11,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
"go.opentelemetry.io/otel/semconv/v1.17.0/httpconv"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/trace"
)
@ -133,10 +132,13 @@ func (t *openTelemetryTransport) Submit(op *runtime.ClientOperation) (interface{
if span != nil {
statusCode := response.Code()
// NOTE: this is replaced by semconv.HTTPResponseStatusCode in semconv v1.21
span.SetAttributes(semconv.HTTPStatusCode(statusCode))
span.SetAttributes(semconv.HTTPResponseStatusCode(statusCode))
// NOTE: the conversion from HTTP status code to trace code is no longer available with
// semconv v1.21
span.SetStatus(httpconv.ServerStatus(statusCode))
const minHTTPStatusIsError = 400
if statusCode >= minHTTPStatusIsError {
span.SetStatus(codes.Error, http.StatusText(statusCode))
}
}
return reader.ReadResponse(response, consumer)
@ -173,7 +175,7 @@ func (t *openTelemetryTransport) newOpenTelemetrySpan(op *runtime.ClientOperatio
span.SetAttributes(
attribute.String("net.peer.name", t.host),
attribute.String(string(semconv.HTTPRouteKey), op.PathPattern),
attribute.String(string(semconv.HTTPMethodKey), op.Method),
attribute.String(string(semconv.HTTPRequestMethodKey), op.Method),
attribute.String("span.kind", trace.SpanKindClient.String()),
attribute.String("http.scheme", scheme),
)

View file

@ -1,99 +0,0 @@
package client
import (
"fmt"
"net/http"
"github.com/go-openapi/strfmt"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/opentracing/opentracing-go/log"
"github.com/go-openapi/runtime"
)
type tracingTransport struct {
transport runtime.ClientTransport
host string
opts []opentracing.StartSpanOption
}
func newOpenTracingTransport(transport runtime.ClientTransport, host string, opts []opentracing.StartSpanOption,
) runtime.ClientTransport {
return &tracingTransport{
transport: transport,
host: host,
opts: opts,
}
}
func (t *tracingTransport) Submit(op *runtime.ClientOperation) (interface{}, error) {
if op.Context == nil {
return t.transport.Submit(op)
}
params := op.Params
reader := op.Reader
var span opentracing.Span
defer func() {
if span != nil {
span.Finish()
}
}()
op.Params = runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
span = createClientSpan(op, req.GetHeaderParams(), t.host, t.opts)
return params.WriteToRequest(req, reg)
})
op.Reader = runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
if span != nil {
code := response.Code()
ext.HTTPStatusCode.Set(span, uint16(code))
if code >= 400 {
ext.Error.Set(span, true)
}
}
return reader.ReadResponse(response, consumer)
})
submit, err := t.transport.Submit(op)
if err != nil && span != nil {
ext.Error.Set(span, true)
span.LogFields(log.Error(err))
}
return submit, err
}
func createClientSpan(op *runtime.ClientOperation, header http.Header, host string,
opts []opentracing.StartSpanOption) opentracing.Span {
ctx := op.Context
span := opentracing.SpanFromContext(ctx)
if span != nil {
opts = append(opts, ext.SpanKindRPCClient)
span, _ = opentracing.StartSpanFromContextWithTracer(
ctx, span.Tracer(), operationName(op), opts...)
ext.Component.Set(span, "go-openapi")
ext.PeerHostname.Set(span, host)
span.SetTag("http.path", op.PathPattern)
ext.HTTPMethod.Set(span, op.Method)
_ = span.Tracer().Inject(
span.Context(),
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(header))
return span
}
return nil
}
func operationName(op *runtime.ClientOperation) string {
if op.ID != "" {
return op.ID
}
return fmt.Sprintf("%s_%s", op.Method, op.PathPattern)
}

View file

@ -30,23 +30,11 @@ import (
"strings"
"time"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
// NewRequest creates a new swagger http client request
func newRequest(method, pathPattern string, writer runtime.ClientRequestWriter) *request {
return &request{
pathPattern: pathPattern,
method: method,
writer: writer,
header: make(http.Header),
query: make(url.Values),
timeout: DefaultTimeout,
getBody: getRequestBuffer,
}
}
var _ runtime.ClientRequest = new(request) // ensure compliance to the interface
// Request represents a swagger client request.
//
@ -67,17 +55,149 @@ type request struct {
query url.Values
formFields url.Values
fileFields map[string][]runtime.NamedReadCloser
payload interface{}
payload any
timeout time.Duration
buf *bytes.Buffer
getBody func(r *request) []byte
}
var (
// ensure interface compliance
_ runtime.ClientRequest = new(request)
)
// NewRequest creates a new swagger http client request
func newRequest(method, pathPattern string, writer runtime.ClientRequestWriter) *request {
return &request{
pathPattern: pathPattern,
method: method,
writer: writer,
header: make(http.Header),
query: make(url.Values),
timeout: DefaultTimeout,
getBody: getRequestBuffer,
}
}
// BuildHTTP creates a new http request based on the data from the params
func (r *request) BuildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry) (*http.Request, error) {
return r.buildHTTP(mediaType, basePath, producers, registry, nil)
}
func (r *request) GetMethod() string {
return r.method
}
func (r *request) GetPath() string {
path := r.pathPattern
for k, v := range r.pathParams {
path = strings.ReplaceAll(path, "{"+k+"}", v)
}
return path
}
func (r *request) GetBody() []byte {
return r.getBody(r)
}
// SetHeaderParam adds a header param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
func (r *request) SetHeaderParam(name string, values ...string) error {
if r.header == nil {
r.header = make(http.Header)
}
r.header[http.CanonicalHeaderKey(name)] = values
return nil
}
// GetHeaderParams returns the all headers currently set for the request
func (r *request) GetHeaderParams() http.Header {
return r.header
}
// SetQueryParam adds a query param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
func (r *request) SetQueryParam(name string, values ...string) error {
if r.query == nil {
r.query = make(url.Values)
}
r.query[name] = values
return nil
}
// GetQueryParams returns a copy of all query params currently set for the request
func (r *request) GetQueryParams() url.Values {
var result = make(url.Values)
for key, value := range r.query {
result[key] = append([]string{}, value...)
}
return result
}
// SetFormParam adds a forn param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
func (r *request) SetFormParam(name string, values ...string) error {
if r.formFields == nil {
r.formFields = make(url.Values)
}
r.formFields[name] = values
return nil
}
// SetPathParam adds a path param to the request
func (r *request) SetPathParam(name string, value string) error {
if r.pathParams == nil {
r.pathParams = make(map[string]string)
}
r.pathParams[name] = value
return nil
}
// SetFileParam adds a file param to the request
func (r *request) SetFileParam(name string, files ...runtime.NamedReadCloser) error {
for _, file := range files {
if actualFile, ok := file.(*os.File); ok {
fi, err := os.Stat(actualFile.Name())
if err != nil {
return err
}
if fi.IsDir() {
return fmt.Errorf("%q is a directory, only files are supported", file.Name())
}
}
}
if r.fileFields == nil {
r.fileFields = make(map[string][]runtime.NamedReadCloser)
}
if r.formFields == nil {
r.formFields = make(url.Values)
}
r.fileFields[name] = files
return nil
}
func (r *request) GetFileParam() map[string][]runtime.NamedReadCloser {
return r.fileFields
}
// SetBodyParam sets a body parameter on the request.
// This does not yet serialze the object, this happens as late as possible.
func (r *request) SetBodyParam(payload any) error {
r.payload = payload
return nil
}
func (r *request) GetBodyParam() any {
return r.payload
}
// SetTimeout sets the timeout for a request
func (r *request) SetTimeout(timeout time.Duration) error {
r.timeout = timeout
return nil
}
func (r *request) isMultipart(mediaType string) bool {
if len(r.fileFields) > 0 {
@ -87,22 +207,6 @@ func (r *request) isMultipart(mediaType string) bool {
return runtime.MultipartFormMime == mediaType
}
// BuildHTTP creates a new http request based on the data from the params
func (r *request) BuildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry) (*http.Request, error) {
return r.buildHTTP(mediaType, basePath, producers, registry, nil)
}
func escapeQuotes(s string) string {
return strings.NewReplacer("\\", "\\\\", `"`, "\\\"").Replace(s)
}
func logClose(err error, pw *io.PipeWriter) {
log.Println(err)
closeErr := pw.CloseWithError(err)
if closeErr != nil {
log.Println(closeErr)
}
}
func (r *request) buildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry, auth runtime.ClientAuthInfoWriter) (*http.Request, error) { //nolint:gocyclo,maintidx
// build the data
if err := r.writer.WriteToRequest(r, registry); err != nil {
@ -169,7 +273,8 @@ func (r *request) buildHTTP(mediaType, basePath string, producers map[string]run
fileContentType = p.ContentType()
} else {
// Need to read the data so that we can detect the content type
buf := make([]byte, 512)
const contentTypeBufferSize = 512
buf := make([]byte, contentTypeBufferSize)
size, err := fi.Read(buf)
if err != nil && err != io.EOF {
logClose(err, pw)
@ -348,27 +453,8 @@ DoneChoosingBodySource:
return req, nil
}
func mangleContentType(mediaType, boundary string) string {
if strings.ToLower(mediaType) == runtime.URLencodedFormMime {
return fmt.Sprintf("%s; boundary=%s", mediaType, boundary)
}
return "multipart/form-data; boundary=" + boundary
}
func (r *request) GetMethod() string {
return r.method
}
func (r *request) GetPath() string {
path := r.pathPattern
for k, v := range r.pathParams {
path = strings.ReplaceAll(path, "{"+k+"}", v)
}
return path
}
func (r *request) GetBody() []byte {
return r.getBody(r)
func escapeQuotes(s string) string {
return strings.NewReplacer("\\", "\\\\", `"`, "\\\"").Replace(s)
}
func getRequestBuffer(r *request) []byte {
@ -378,105 +464,17 @@ func getRequestBuffer(r *request) []byte {
return r.buf.Bytes()
}
// SetHeaderParam adds a header param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
func (r *request) SetHeaderParam(name string, values ...string) error {
if r.header == nil {
r.header = make(http.Header)
func logClose(err error, pw *io.PipeWriter) {
log.Println(err)
closeErr := pw.CloseWithError(err)
if closeErr != nil {
log.Println(closeErr)
}
r.header[http.CanonicalHeaderKey(name)] = values
return nil
}
// GetHeaderParams returns the all headers currently set for the request
func (r *request) GetHeaderParams() http.Header {
return r.header
}
// SetQueryParam adds a query param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
func (r *request) SetQueryParam(name string, values ...string) error {
if r.query == nil {
r.query = make(url.Values)
func mangleContentType(mediaType, boundary string) string {
if strings.ToLower(mediaType) == runtime.URLencodedFormMime {
return fmt.Sprintf("%s; boundary=%s", mediaType, boundary)
}
r.query[name] = values
return nil
}
// GetQueryParams returns a copy of all query params currently set for the request
func (r *request) GetQueryParams() url.Values {
var result = make(url.Values)
for key, value := range r.query {
result[key] = append([]string{}, value...)
}
return result
}
// SetFormParam adds a forn param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
func (r *request) SetFormParam(name string, values ...string) error {
if r.formFields == nil {
r.formFields = make(url.Values)
}
r.formFields[name] = values
return nil
}
// SetPathParam adds a path param to the request
func (r *request) SetPathParam(name string, value string) error {
if r.pathParams == nil {
r.pathParams = make(map[string]string)
}
r.pathParams[name] = value
return nil
}
// SetFileParam adds a file param to the request
func (r *request) SetFileParam(name string, files ...runtime.NamedReadCloser) error {
for _, file := range files {
if actualFile, ok := file.(*os.File); ok {
fi, err := os.Stat(actualFile.Name())
if err != nil {
return err
}
if fi.IsDir() {
return fmt.Errorf("%q is a directory, only files are supported", file.Name())
}
}
}
if r.fileFields == nil {
r.fileFields = make(map[string][]runtime.NamedReadCloser)
}
if r.formFields == nil {
r.formFields = make(url.Values)
}
r.fileFields[name] = files
return nil
}
func (r *request) GetFileParam() map[string][]runtime.NamedReadCloser {
return r.fileFields
}
// SetBodyParam sets a body parameter on the request.
// This does not yet serialze the object, this happens as late as possible.
func (r *request) SetBodyParam(payload interface{}) error {
r.payload = payload
return nil
}
func (r *request) GetBodyParam() interface{} {
return r.payload
}
// SetTimeout sets the timeout for a request
func (r *request) SetTimeout(timeout time.Duration) error {
r.timeout = timeout
return nil
return "multipart/form-data; boundary=" + boundary
}

View file

@ -32,13 +32,11 @@ import (
"sync"
"time"
"github.com/go-openapi/strfmt"
"github.com/opentracing/opentracing-go"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/runtime/yamlpc"
"github.com/go-openapi/strfmt"
)
const (
@ -46,6 +44,9 @@ const (
schemeHTTPS = "https"
)
// DefaultTimeout the default request timeout
var DefaultTimeout = 30 * time.Second
// TLSClientOptions to configure client authentication with mutual TLS
type TLSClientOptions struct {
// Certificate is the path to a PEM-encoded certificate to be used for
@ -193,13 +194,6 @@ func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
return cfg, nil
}
func basePool(pool *x509.CertPool) *x509.CertPool {
if pool == nil {
return x509.NewCertPool()
}
return pool
}
// TLSTransport creates a http client transport suitable for mutual tls auth
func TLSTransport(opts TLSClientOptions) (http.RoundTripper, error) {
cfg, err := TLSClientAuth(opts)
@ -219,9 +213,6 @@ func TLSClient(opts TLSClientOptions) (*http.Client, error) {
return &http.Client{Transport: transport}, nil
}
// DefaultTimeout the default request timeout
var DefaultTimeout = 30 * time.Second
// Runtime represents an API client that uses the transport
// to make http requests based on a swagger specification.
type Runtime struct {
@ -306,8 +297,33 @@ func NewWithClient(host, basePath string, schemes []string, client *http.Client)
// A new client span is created for each request.
// If the context of the client operation does not contain an active span, no span is created.
// The provided opts are applied to each spans - for example to add global tags.
func (r *Runtime) WithOpenTracing(opts ...opentracing.StartSpanOption) runtime.ClientTransport {
return newOpenTracingTransport(r, r.Host, opts)
//
// Deprecated: use [WithOpenTelemetry] instead, as opentracing is now archived and superseded by opentelemetry.
//
// # Deprecation notice
//
// The [Runtime.WithOpenTracing] method has been deprecated in favor of [Runtime.WithOpenTelemetry].
//
// The method is still around so programs calling it will still build. However, it will return
// an opentelemetry transport.
//
// If you have a strict requirement on using opentracing, you may still do so by importing
// module [github.com/go-openapi/runtime/client-middleware/opentracing] and using
// [github.com/go-openapi/runtime/client-middleware/opentracing.WithOpenTracing] with your
// usual opentracing options and opentracing-enabled transport.
//
// Passed options are ignored unless they are of type [OpenTelemetryOpt].
func (r *Runtime) WithOpenTracing(opts ...any) runtime.ClientTransport {
otelOpts := make([]OpenTelemetryOpt, 0, len(opts))
for _, o := range opts {
otelOpt, ok := o.(OpenTelemetryOpt)
if !ok {
continue
}
otelOpts = append(otelOpts, otelOpt)
}
return r.WithOpenTelemetry(otelOpts...)
}
// WithOpenTelemetry adds opentelemetry support to the provided runtime.
@ -318,42 +334,6 @@ func (r *Runtime) WithOpenTelemetry(opts ...OpenTelemetryOpt) runtime.ClientTran
return newOpenTelemetryTransport(r, r.Host, opts)
}
func (r *Runtime) pickScheme(schemes []string) string {
if v := r.selectScheme(r.schemes); v != "" {
return v
}
if v := r.selectScheme(schemes); v != "" {
return v
}
return schemeHTTP
}
func (r *Runtime) selectScheme(schemes []string) string {
schLen := len(schemes)
if schLen == 0 {
return ""
}
scheme := schemes[0]
// prefer https, but skip when not possible
if scheme != schemeHTTPS && schLen > 1 {
for _, sch := range schemes {
if sch == schemeHTTPS {
scheme = sch
break
}
}
}
return scheme
}
func transportOrDefault(left, right http.RoundTripper) http.RoundTripper {
if left == nil {
return right
}
return left
}
// EnableConnectionReuse drains the remaining body from a response
// so that go will reuse the TCP connections.
//
@ -376,57 +356,7 @@ func (r *Runtime) EnableConnectionReuse() {
)
}
// takes a client operation and creates equivalent http.Request
func (r *Runtime) createHttpRequest(operation *runtime.ClientOperation) (*request, *http.Request, error) { //nolint:revive,stylecheck
params, _, auth := operation.Params, operation.Reader, operation.AuthInfo
request := newRequest(operation.Method, operation.PathPattern, params)
var accept []string
accept = append(accept, operation.ProducesMediaTypes...)
if err := request.SetHeaderParam(runtime.HeaderAccept, accept...); err != nil {
return nil, nil, err
}
if auth == nil && r.DefaultAuthentication != nil {
auth = runtime.ClientAuthInfoWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
if req.GetHeaderParams().Get(runtime.HeaderAuthorization) != "" {
return nil
}
return r.DefaultAuthentication.AuthenticateRequest(req, reg)
})
}
// if auth != nil {
// if err := auth.AuthenticateRequest(request, r.Formats); err != nil {
// return nil, err
// }
//}
// TODO: pick appropriate media type
cmt := r.DefaultMediaType
for _, mediaType := range operation.ConsumesMediaTypes {
// Pick first non-empty media type
if mediaType != "" {
cmt = mediaType
break
}
}
if _, ok := r.Producers[cmt]; !ok && cmt != runtime.MultipartFormMime && cmt != runtime.URLencodedFormMime {
return nil, nil, fmt.Errorf("none of producers: %v registered. try %s", r.Producers, cmt)
}
req, err := request.buildHTTP(cmt, r.BasePath, r.Producers, r.Formats, auth)
if err != nil {
return nil, nil, err
}
req.URL.Scheme = r.pickScheme(operation.Schemes)
req.URL.Host = r.Host
req.Host = r.Host
return request, req, nil
}
func (r *Runtime) CreateHttpRequest(operation *runtime.ClientOperation) (req *http.Request, err error) { //nolint:revive,stylecheck
func (r *Runtime) CreateHttpRequest(operation *runtime.ClientOperation) (req *http.Request, err error) { //nolint:revive
_, req, err = r.createHttpRequest(operation)
return
}
@ -550,3 +480,96 @@ func (r *Runtime) SetResponseReader(f ClientResponseFunc) {
}
r.response = f
}
func (r *Runtime) pickScheme(schemes []string) string {
if v := r.selectScheme(r.schemes); v != "" {
return v
}
if v := r.selectScheme(schemes); v != "" {
return v
}
return schemeHTTP
}
func (r *Runtime) selectScheme(schemes []string) string {
schLen := len(schemes)
if schLen == 0 {
return ""
}
scheme := schemes[0]
// prefer https, but skip when not possible
if scheme != schemeHTTPS && schLen > 1 {
for _, sch := range schemes {
if sch == schemeHTTPS {
scheme = sch
break
}
}
}
return scheme
}
func transportOrDefault(left, right http.RoundTripper) http.RoundTripper {
if left == nil {
return right
}
return left
}
// takes a client operation and creates equivalent http.Request
func (r *Runtime) createHttpRequest(operation *runtime.ClientOperation) (*request, *http.Request, error) { //nolint:revive
params, _, auth := operation.Params, operation.Reader, operation.AuthInfo
request := newRequest(operation.Method, operation.PathPattern, params)
var accept []string
accept = append(accept, operation.ProducesMediaTypes...)
if err := request.SetHeaderParam(runtime.HeaderAccept, accept...); err != nil {
return nil, nil, err
}
if auth == nil && r.DefaultAuthentication != nil {
auth = runtime.ClientAuthInfoWriterFunc(func(req runtime.ClientRequest, reg strfmt.Registry) error {
if req.GetHeaderParams().Get(runtime.HeaderAuthorization) != "" {
return nil
}
return r.DefaultAuthentication.AuthenticateRequest(req, reg)
})
}
// if auth != nil {
// if err := auth.AuthenticateRequest(request, r.Formats); err != nil {
// return nil, err
// }
//}
// TODO: pick appropriate media type
cmt := r.DefaultMediaType
for _, mediaType := range operation.ConsumesMediaTypes {
// Pick first non-empty media type
if mediaType != "" {
cmt = mediaType
break
}
}
if _, ok := r.Producers[cmt]; !ok && cmt != runtime.MultipartFormMime && cmt != runtime.URLencodedFormMime {
return nil, nil, fmt.Errorf("none of producers: %v registered. try %s", r.Producers, cmt)
}
req, err := request.buildHTTP(cmt, r.BasePath, r.Producers, r.Formats, auth)
if err != nil {
return nil, nil, err
}
req.URL.Scheme = r.pickScheme(operation.Schemes)
req.URL.Host = r.Host
req.Host = r.Host
return request, req, nil
}
func basePool(pool *x509.CertPool) *x509.CertPool {
if pool == nil {
return x509.NewCertPool()
}
return pool
}

View file

@ -20,7 +20,8 @@ import (
"io"
)
// A ClientResponse represents a client response
// A ClientResponse represents a client response.
//
// This bridges between responses obtained from different transports
type ClientResponse interface {
Code() int
@ -44,6 +45,13 @@ type ClientResponseReader interface {
ReadResponse(ClientResponse, Consumer) (interface{}, error)
}
// APIError wraps an error model and captures the status code
type APIError struct {
OperationName string
Response interface{}
Code int
}
// NewAPIError creates a new API error
func NewAPIError(opName string, payload interface{}, code int) *APIError {
return &APIError{
@ -53,13 +61,6 @@ func NewAPIError(opName string, payload interface{}, code int) *APIError {
}
}
// APIError wraps an error model and captures the status code
type APIError struct {
OperationName string
Response interface{}
Code int
}
func (o *APIError) Error() string {
var resp []byte
if err, ok := o.Response.(error); ok {
@ -74,27 +75,31 @@ func (o *APIError) String() string {
return o.Error()
}
// IsSuccess returns true when this elapse o k response returns a 2xx status code
// IsSuccess returns true when this API response returns a 2xx status code
func (o *APIError) IsSuccess() bool {
return o.Code/100 == 2
const statusOK = 2
return o.Code/100 == statusOK
}
// IsRedirect returns true when this elapse o k response returns a 3xx status code
// IsRedirect returns true when this API response returns a 3xx status code
func (o *APIError) IsRedirect() bool {
return o.Code/100 == 3
const statusRedirect = 3
return o.Code/100 == statusRedirect
}
// IsClientError returns true when this elapse o k response returns a 4xx status code
// IsClientError returns true when this API response returns a 4xx status code
func (o *APIError) IsClientError() bool {
return o.Code/100 == 4
const statusClientError = 4
return o.Code/100 == statusClientError
}
// IsServerError returns true when this elapse o k response returns a 5xx status code
// IsServerError returns true when this API response returns a 5xx status code
func (o *APIError) IsServerError() bool {
return o.Code/100 == 5
const statusServerError = 5
return o.Code/100 == statusServerError
}
// IsCode returns true when this elapse o k response returns a 4xx status code
// IsCode returns true when this API response returns a given status code
func (o *APIError) IsCode(code int) bool {
return o.Code == code
}

View file

@ -5,7 +5,7 @@ import (
"io"
)
// CSVOpts alter the behavior of the CSV consumer or producer.
// CSVOpt alter the behavior of the CSV consumer or producer.
type CSVOpt func(*csvOpts)
type csvOpts struct {

View file

@ -14,6 +14,6 @@
package runtime
import "github.com/go-openapi/swag"
import "github.com/go-openapi/swag/fileutils"
type File = swag.File
type File = fileutils.File

6
vendor/github.com/go-openapi/runtime/go.work generated vendored Normal file
View file

@ -0,0 +1,6 @@
use (
.
./client-middleware/opentracing
)
go 1.24.0

88
vendor/github.com/go-openapi/runtime/go.work.sum generated vendored Normal file
View file

@ -0,0 +1,88 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/go-openapi/errors v0.22.2/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0=
github.com/go-openapi/jsonpointer v0.22.0/go.mod h1:xt3jV88UtExdIkkL7NloURjRQjbeUgcxFblMjq2iaiU=
github.com/go-openapi/jsonreference v0.21.1/go.mod h1:PWs8rO4xxTUqKGu+lEvvCxD5k2X7QYkKAepJyCmSTT8=
github.com/go-openapi/swag v0.24.1/go.mod h1:sm8I3lCPlspsBBwUm1t5oZeWZS0s7m/A+Psg0ooRU0A=
github.com/go-openapi/swag/cmdutils v0.24.0/go.mod h1:uxib2FAeQMByyHomTlsP8h1TtPd54Msu2ZDU/H5Vuf8=
github.com/go-openapi/swag/conv v0.24.0/go.mod h1:jbn140mZd7EW2g8a8Y5bwm8/Wy1slLySQQ0ND6DPc2c=
github.com/go-openapi/swag/fileutils v0.24.0/go.mod h1:3SCrCSBHyP1/N+3oErQ1gP+OX1GV2QYFSnrTbzwli90=
github.com/go-openapi/swag/jsonname v0.24.0/go.mod h1:GXqrPzGJe611P7LG4QB9JKPtUZ7flE4DOVechNaDd7Q=
github.com/go-openapi/swag/jsonutils v0.24.0/go.mod h1:vBowZtF5Z4DDApIoxcIVfR8v0l9oq5PpYRUuteVu6f0=
github.com/go-openapi/swag/loading v0.24.0/go.mod h1:gShCN4woKZYIxPxbfbyHgjXAhO61m88tmjy0lp/LkJk=
github.com/go-openapi/swag/mangling v0.24.0/go.mod h1:Jm5Go9LHkycsz0wfoaBDkdc4CkpuSnIEf62brzyCbhc=
github.com/go-openapi/swag/netutils v0.24.0/go.mod h1:WRgiHcYTnx+IqfMCtu0hy9oOaPR0HnPbmArSRN1SkZM=
github.com/go-openapi/swag/stringutils v0.24.0/go.mod h1:5nUXB4xA0kw2df5PRipZDslPJgJut+NjL7D25zPZ/4w=
github.com/go-openapi/swag/typeutils v0.24.0/go.mod h1:q8C3Kmk/vh2VhpCLaoR2MVWOGP8y7Jc8l82qCTd1DYI=
github.com/go-openapi/swag/yamlutils v0.24.0/go.mod h1:DpKv5aYuaGm/sULePoeiG8uwMpZSfReo1HR3Ik0yaG8=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/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.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -218,8 +218,8 @@ func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Ro
// 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 {
// Either there are no spec doc and analysis, or both of them.
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"))
if (spec != nil || an != nil) && (spec == nil || an == nil) {
panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, "routable context requires either both spec doc and analysis, or none of them"))
}
return &Context{
@ -307,6 +307,9 @@ type contentTypeValue struct {
// BasePath returns the base path for this API
func (c *Context) BasePath() string {
if c.spec == nil {
return ""
}
return c.spec.BasePath()
}
@ -341,7 +344,7 @@ func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, b
if len(res) == 0 {
cons, ok := route.Consumers[ct]
if !ok {
res = append(res, errors.New(500, "no consumer registered for %s", ct))
res = append(res, errors.New(http.StatusInternalServerError, "no consumer registered for %s", ct))
} else {
route.Consumer = cons
requestContentType = ct
@ -486,7 +489,7 @@ func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (interfa
return nil, nil, err
}
return nil, nil, errors.New(http.StatusForbidden, err.Error())
return nil, nil, errors.New(http.StatusForbidden, "%v", err)
}
}
@ -552,7 +555,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
pr, ok := prods[c.api.DefaultProduces()]
if !ok {
panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
}
prod = pr
}
@ -585,7 +588,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
producers := c.api.ProducersFor(normalizeOffers(offers))
prod, ok := producers[format]
if !ok {
panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
}
if err := prod.Produce(rw, data); err != nil {
panic(err) // let the recovery middleware deal with this
@ -606,7 +609,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
prods := c.api.ProducersFor(normalizeOffers([]string{c.api.DefaultProduces()}))
pr, ok := prods[c.api.DefaultProduces()]
if !ok {
panic(errors.New(http.StatusInternalServerError, cantFindProducer(format)))
panic(fmt.Errorf("%d: %s", http.StatusInternalServerError, cantFindProducer(format)))
}
prod = pr
}
@ -617,7 +620,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
return
}
c.api.ServeErrorFor(route.Operation.ID)(rw, r, errors.New(http.StatusInternalServerError, "can't produce response"))
c.api.ServeErrorFor(route.Operation.ID)(rw, r, fmt.Errorf("%d: %s", http.StatusInternalServerError, "can't produce response"))
}
// APIHandlerSwaggerUI returns a handler to serve the API.
@ -677,6 +680,15 @@ func (c *Context) APIHandler(builder Builder, opts ...UIOption) http.Handler {
return Spec(specPath, c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b)), specOpts...)
}
// RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec
func (c *Context) RoutesHandler(builder Builder) http.Handler {
b := builder
if b == nil {
b = PassthroughBuilder
}
return NewRouter(c, b(NewOperationExecutor(c)))
}
func (c Context) uiOptionsForHandler(opts []UIOption) (string, uiOptions, []SpecOption) {
var title string
sp := c.spec.Spec()
@ -708,15 +720,6 @@ func (c Context) uiOptionsForHandler(opts []UIOption) (string, uiOptions, []Spec
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
func (c *Context) RoutesHandler(builder Builder) http.Handler {
b := builder
if b == nil {
b = PassthroughBuilder
}
return NewRouter(c, b(NewOperationExecutor(c)))
}
func cantFindProducer(format string) string {
return "can't find a producer for " + format
}

View file

@ -25,7 +25,7 @@ const (
PathParamCharacter = '='
// MaxSize is max size of records and internal slice.
MaxSize = (1 << 22) - 1
MaxSize = (1 << 22) - 1 //nolint:mnd
)
// Router represents a URL router.
@ -62,7 +62,7 @@ func (rt *Router) Lookup(path string) (data interface{}, params Params, found bo
if !found {
return nil, nil, false
}
for i := 0; i < len(params); i++ {
for i := range params {
params[i].Name = nd.paramNames[i]
}
return nd.data, params, true
@ -138,12 +138,17 @@ func newDoubleArray() *doubleArray {
// 32 10 8 0
type baseCheck uint32
const (
flagsBits = 10
checkBits = 8
)
func (bc baseCheck) Base() int {
return int(bc >> 10)
return int(bc >> flagsBits)
}
func (bc *baseCheck) SetBase(base int) {
*bc |= baseCheck(base) << 10
*bc |= baseCheck(base) << flagsBits //nolint:gosec // integer conversion is ok
}
func (bc baseCheck) Check() byte {
@ -171,24 +176,27 @@ func (bc baseCheck) IsAnyParam() bool {
}
func (bc *baseCheck) SetSingleParam() {
*bc |= (1 << 8)
*bc |= (1 << checkBits)
}
func (bc *baseCheck) SetWildcardParam() {
*bc |= (1 << 9)
*bc |= (1 << (checkBits + 1))
}
const (
paramTypeSingle = 0x0100
paramTypeWildcard = 0x0200
paramTypeAny = 0x0300
indexOffset = 32
indexMask = uint64(0xffffffff)
)
func (da *doubleArray) lookup(path string, params []Param, idx int) (*node, []Param, bool) {
indices := make([]uint64, 0, 1)
for i := 0; i < len(path); i++ {
for i := range len(path) {
if da.bc[idx].IsAnyParam() {
indices = append(indices, (uint64(i)<<32)|(uint64(idx)&0xffffffff))
indices = append(indices, (uint64(i)<<indexOffset)|(uint64(idx)&indexMask)) //nolint:gosec // integer conversion is okay
}
c := path[i]
if idx = nextIndex(da.bc[idx].Base(), c); idx >= len(da.bc) || da.bc[idx].Check() != c {
@ -201,7 +209,7 @@ func (da *doubleArray) lookup(path string, params []Param, idx int) (*node, []Pa
BACKTRACKING:
for j := len(indices) - 1; j >= 0; j-- {
i, idx := int(indices[j]>>32), int(indices[j]&0xffffffff)
i, idx := int(indices[j]>>indexOffset), int(indices[j]&indexMask) //nolint:gosec // integer conversion is okay
if da.bc[idx].IsSingleParam() {
nextIdx := nextIndex(da.bc[idx].Base(), ParamCharacter)
if nextIdx >= len(da.bc) {
@ -428,6 +436,7 @@ func NewRecord(key string, value interface{}) Record {
// record represents a record that use to build the Double-Array.
type record struct {
Record
paramNames []string
}

View file

@ -25,6 +25,11 @@ const (
isSpace
)
const (
asciiMaxControlChar = 31
asciiMaxChar = 127
)
func init() {
// OCTET = <any 8-bit sequence of data>
// CHAR = <any US-ASCII character (octets 0 - 127)>
@ -42,10 +47,10 @@ func init() {
// token = 1*<any CHAR except CTLs or separators>
// qdtext = <any TEXT except <">>
for c := 0; c < 256; c++ {
for c := range 256 {
var t octetType
isCtl := c <= 31 || c == 127
isChar := 0 <= c && c <= 127
isCtl := c <= asciiMaxControlChar || c == asciiMaxChar
isChar := 0 <= c && c <= asciiMaxChar
isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
if strings.ContainsRune(" \t\r\n", rune(c)) {
t |= isSpace
@ -92,7 +97,7 @@ func ParseList(header http.Header, key string) []string {
end := 0
escape := false
quote := false
for i := 0; i < len(s); i++ {
for i := range len(s) {
b := s[i]
switch {
case escape:

View file

@ -94,5 +94,6 @@ func normalizeOffers(orig []string) (norm []string) {
}
func normalizeOffer(orig string) string {
return strings.SplitN(orig, ";", 2)[0]
const maxParts = 2
return strings.SplitN(orig, ";", maxParts)[0]
}

View file

@ -24,12 +24,12 @@ import (
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/conv"
"github.com/go-openapi/swag/stringutils"
"github.com/go-openapi/validate"
"github.com/go-openapi/runtime"
)
const defaultMaxMemory = 32 << 20
@ -66,85 +66,6 @@ func (p *untypedParamBinder) Type() reflect.Type {
return p.typeForSchema(p.parameter.Type, p.parameter.Format, p.parameter.Items)
}
func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items) reflect.Type {
switch tpe {
case "boolean":
return reflect.TypeOf(true)
case typeString:
if tt, ok := p.formats.GetType(format); ok {
return tt
}
return reflect.TypeOf("")
case "integer":
switch format {
case "int8":
return reflect.TypeOf(int8(0))
case "int16":
return reflect.TypeOf(int16(0))
case "int32":
return reflect.TypeOf(int32(0))
case "int64":
return reflect.TypeOf(int64(0))
default:
return reflect.TypeOf(int64(0))
}
case "number":
switch format {
case "float":
return reflect.TypeOf(float32(0))
case "double":
return reflect.TypeOf(float64(0))
}
case typeArray:
if items == nil {
return nil
}
itemsType := p.typeForSchema(items.Type, items.Format, items.Items)
if itemsType == nil {
return nil
}
return reflect.MakeSlice(reflect.SliceOf(itemsType), 0, 0).Type()
case "file":
return reflect.TypeOf(&runtime.File{}).Elem()
case "object":
return reflect.TypeOf(map[string]interface{}{})
}
return nil
}
func (p *untypedParamBinder) allowsMulti() bool {
return p.parameter.In == "query" || p.parameter.In == "formData"
}
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
if tpe == typeArray {
if cf == "multi" {
if !p.allowsMulti() {
return nil, false, false, errors.InvalidCollectionFormat(name, in, cf)
}
vv, hasKey, _ := values.GetOK(name)
return vv, false, hasKey, nil
}
v, hk, hv := values.GetOK(name)
if !hv {
return nil, false, hk, nil
}
d, c, e := p.readFormattedSliceFieldValue(v[len(v)-1], target)
return d, c, hk, e
}
vv, hk, _ := values.GetOK(name)
return vv, false, hk, nil
}
func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, target reflect.Value) error {
// fmt.Println("binding", p.name, "as", p.Type())
switch p.parameter.In {
@ -264,10 +185,89 @@ func (p *untypedParamBinder) Bind(request *http.Request, routeParams RouteParams
target.Set(reflect.Indirect(newValue))
return nil
default:
return errors.New(500, fmt.Sprintf("invalid parameter location %q", p.parameter.In))
return fmt.Errorf("%d: invalid parameter location %q", http.StatusInternalServerError, p.parameter.In)
}
}
func (p *untypedParamBinder) typeForSchema(tpe, format string, items *spec.Items) reflect.Type {
switch tpe {
case "boolean":
return reflect.TypeOf(true)
case typeString:
if tt, ok := p.formats.GetType(format); ok {
return tt
}
return reflect.TypeOf("")
case "integer":
switch format {
case "int8":
return reflect.TypeOf(int8(0))
case "int16":
return reflect.TypeOf(int16(0))
case "int32":
return reflect.TypeOf(int32(0))
case "int64":
return reflect.TypeOf(int64(0))
default:
return reflect.TypeOf(int64(0))
}
case "number":
switch format {
case "float":
return reflect.TypeOf(float32(0))
case "double":
return reflect.TypeOf(float64(0))
}
case typeArray:
if items == nil {
return nil
}
itemsType := p.typeForSchema(items.Type, items.Format, items.Items)
if itemsType == nil {
return nil
}
return reflect.MakeSlice(reflect.SliceOf(itemsType), 0, 0).Type()
case "file":
return reflect.TypeOf(&runtime.File{}).Elem()
case "object":
return reflect.TypeOf(map[string]interface{}{})
}
return nil
}
func (p *untypedParamBinder) allowsMulti() bool {
return p.parameter.In == "query" || p.parameter.In == "formData"
}
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
if tpe == typeArray {
if cf == "multi" {
if !p.allowsMulti() {
return nil, false, false, errors.InvalidCollectionFormat(name, in, cf)
}
vv, hasKey, _ := values.GetOK(name)
return vv, false, hasKey, nil
}
v, hk, hv := values.GetOK(name)
if !hv {
return nil, false, hk, nil
}
d, c, e := p.readFormattedSliceFieldValue(v[len(v)-1], target)
return d, c, hk, e
}
vv, hk, _ := values.GetOK(name)
return vv, false, hk, nil
}
func (p *untypedParamBinder) bindValue(data []string, hasKey bool, target reflect.Value) error {
if p.parameter.Type == typeArray {
return p.setSliceFieldValue(target, p.parameter.Default, data, hasKey)
@ -331,7 +331,7 @@ func (p *untypedParamBinder) setFieldValue(target reflect.Value, defaultValue in
}
return nil
}
b, err := swag.ConvertBool(data)
b, err := conv.ConvertBool(data)
if err != nil {
return err
}
@ -431,7 +431,7 @@ func (p *untypedParamBinder) tryUnmarshaler(target reflect.Value, defaultValue i
return false, nil
}
// When a type implements encoding.TextUnmarshaler we'll use that instead of reflecting some more
if reflect.PtrTo(target.Type()).Implements(textUnmarshalType) {
if reflect.PointerTo(target.Type()).Implements(textUnmarshalType) {
if defaultValue != nil && len(data) == 0 {
target.Set(reflect.ValueOf(defaultValue))
return true, nil
@ -455,7 +455,7 @@ func (p *untypedParamBinder) readFormattedSliceFieldValue(data string, target re
return nil, true, nil
}
return swag.SplitByFormat(data, p.parameter.CollectionFormat), false, nil
return stringutils.SplitByFormat(data, p.parameter.CollectionFormat), false, nil
}
func (p *untypedParamBinder) setSliceFieldValue(target reflect.Value, defaultValue interface{}, data []string, hasKey bool) error {
@ -479,7 +479,7 @@ func (p *untypedParamBinder) setSliceFieldValue(target reflect.Value, defaultVal
value := reflect.MakeSlice(reflect.SliceOf(target.Type().Elem()), sz, sz)
for i := 0; i < sz; i++ {
for i := range sz {
if err := p.setFieldValue(value.Index(i), nil, data[i], hasKey); err != nil {
return err
}

View file

@ -77,7 +77,7 @@ func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RoutePara
}
if !target.IsValid() {
result = append(result, errors.New(500, "parameter name %q is an unknown field", binder.Name))
result = append(result, errors.New(http.StatusInternalServerError, "parameter name %q is an unknown field", binder.Name))
continue
}

View file

@ -22,18 +22,16 @@ import (
"regexp"
"strings"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/security"
"github.com/go-openapi/swag"
"github.com/go-openapi/analysis"
"github.com/go-openapi/errors"
"github.com/go-openapi/loads"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/middleware/denco"
"github.com/go-openapi/runtime/security"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware/denco"
"github.com/go-openapi/swag/stringutils"
)
// RouteParam is a object to capture route params in a framework agnostic way.
@ -336,6 +334,7 @@ type routeEntry struct {
// MatchedRoute represents the route that was matched in this request
type MatchedRoute struct {
routeEntry
Params RouteParams
Consumer runtime.Consumer
Producer runtime.Producer
@ -377,7 +376,8 @@ func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
}
// a workaround to handle fragment/composing parameters until they are supported in denco router
// check if this parameter is a fragment within a path segment
if xpos := strings.Index(entry.PathPattern, fmt.Sprintf("{%s}", p.Name)) + len(p.Name) + 2; xpos < len(entry.PathPattern) && entry.PathPattern[xpos] != '/' {
const enclosureSize = 2
if xpos := strings.Index(entry.PathPattern, fmt.Sprintf("{%s}", p.Name)) + len(p.Name) + enclosureSize; xpos < len(entry.PathPattern) && entry.PathPattern[xpos] != '/' {
// extract fragment parameters
ep := strings.Split(entry.PathPattern[xpos:], "/")[0]
pnames, pvalues := decodeCompositParams(p.Name, v, ep, nil, nil)
@ -460,11 +460,11 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
parameters := d.analyzer.ParamsFor(method, strings.TrimPrefix(path, bp))
// add API defaults if not part of the spec
if defConsumes := d.api.DefaultConsumes(); defConsumes != "" && !swag.ContainsStringsCI(consumes, defConsumes) {
if defConsumes := d.api.DefaultConsumes(); defConsumes != "" && !stringutils.ContainsStringsCI(consumes, defConsumes) {
consumes = append(consumes, defConsumes)
}
if defProduces := d.api.DefaultProduces(); defProduces != "" && !swag.ContainsStringsCI(produces, defProduces) {
if defProduces := d.api.DefaultProduces(); defProduces != "" && !stringutils.ContainsStringsCI(produces, defProduces) {
produces = append(produces, defProduces)
}
@ -489,6 +489,20 @@ func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Oper
}
}
func (d *defaultRouteBuilder) Build() *defaultRouter {
routers := make(map[string]*denco.Router)
for method, records := range d.records {
router := denco.New()
_ = router.Build(records)
routers[method] = router
}
return &defaultRouter{
spec: d.spec,
routers: routers,
debugLogf: d.debugLogf,
}
}
func (d *defaultRouteBuilder) buildAuthenticators(operation *spec.Operation) RouteAuthenticators {
requirements := d.analyzer.SecurityRequirementsFor(operation)
auths := make([]RouteAuthenticator, 0, len(requirements))
@ -515,17 +529,3 @@ func (d *defaultRouteBuilder) buildAuthenticators(operation *spec.Operation) Rou
}
return auths
}
func (d *defaultRouteBuilder) Build() *defaultRouter {
routers := make(map[string]*denco.Router)
for method, records := range d.records {
router := denco.New()
_ = router.Build(records)
routers[method] = router
}
return &defaultRouter{
spec: d.spec,
routers: routers,
debugLogf: d.debugLogf,
}
}

View file

@ -168,6 +168,6 @@ func serveUI(pth string, assets []byte, next http.Handler) http.Handler {
rw.Header().Set(contentTypeHeader, "text/plain")
rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
_, _ = fmt.Fprintf(rw, "%q not found", pth)
})
}

View file

@ -29,25 +29,10 @@ import (
"github.com/go-openapi/runtime"
)
// NewAPI creates the default untyped API
func NewAPI(spec *loads.Document) *API {
var an *analysis.Spec
if spec != nil && spec.Spec() != nil {
an = analysis.New(spec.Spec())
}
api := &API{
spec: spec,
analyzer: an,
consumers: make(map[string]runtime.Consumer, 10),
producers: make(map[string]runtime.Producer, 10),
authenticators: make(map[string]runtime.Authenticator),
operations: make(map[string]map[string]runtime.OperationHandler),
ServeError: errors.ServeError,
Models: make(map[string]func() interface{}),
formats: strfmt.NewFormats(),
}
return api.WithJSONDefaults()
}
const (
smallPreallocatedSlots = 10
mediumPreallocatedSlots = 30
)
// API represents an untyped mux for a swagger spec
type API struct {
@ -61,10 +46,31 @@ type API struct {
authorizer runtime.Authorizer
operations map[string]map[string]runtime.OperationHandler
ServeError func(http.ResponseWriter, *http.Request, error)
Models map[string]func() interface{}
Models map[string]func() any
formats strfmt.Registry
}
// NewAPI creates the default untyped API
func NewAPI(spec *loads.Document) *API {
var an *analysis.Spec
if spec != nil && spec.Spec() != nil {
an = analysis.New(spec.Spec())
}
api := &API{
spec: spec,
analyzer: an,
consumers: make(map[string]runtime.Consumer, smallPreallocatedSlots),
producers: make(map[string]runtime.Producer, smallPreallocatedSlots),
authenticators: make(map[string]runtime.Authenticator),
operations: make(map[string]map[string]runtime.OperationHandler),
ServeError: errors.ServeError,
Models: make(map[string]func() any),
formats: strfmt.NewFormats(),
}
return api.WithJSONDefaults()
}
// WithJSONDefaults loads the json defaults for this api
func (d *API) WithJSONDefaults() *API {
d.DefaultConsumes = runtime.JSONMime
@ -115,7 +121,7 @@ func (d *API) RegisterAuthorizer(handler runtime.Authorizer) {
// RegisterConsumer registers a consumer for a media type.
func (d *API) RegisterConsumer(mediaType string, handler runtime.Consumer) {
if d.consumers == nil {
d.consumers = make(map[string]runtime.Consumer, 10)
d.consumers = make(map[string]runtime.Consumer, smallPreallocatedSlots)
}
d.consumers[strings.ToLower(mediaType)] = handler
}
@ -123,7 +129,7 @@ func (d *API) RegisterConsumer(mediaType string, handler runtime.Consumer) {
// RegisterProducer registers a producer for a media type
func (d *API) RegisterProducer(mediaType string, handler runtime.Producer) {
if d.producers == nil {
d.producers = make(map[string]runtime.Producer, 10)
d.producers = make(map[string]runtime.Producer, smallPreallocatedSlots)
}
d.producers[strings.ToLower(mediaType)] = handler
}
@ -131,7 +137,7 @@ func (d *API) RegisterProducer(mediaType string, handler runtime.Producer) {
// RegisterOperation registers an operation handler for an operation name
func (d *API) RegisterOperation(method, path string, handler runtime.OperationHandler) {
if d.operations == nil {
d.operations = make(map[string]map[string]runtime.OperationHandler, 30)
d.operations = make(map[string]map[string]runtime.OperationHandler, mediumPreallocatedSlots)
}
um := strings.ToUpper(method)
if b, ok := d.operations[um]; !ok || b == nil {

View file

@ -20,9 +20,8 @@ import (
"strings"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/runtime"
"github.com/go-openapi/swag/stringutils"
)
type validation struct {
@ -30,7 +29,7 @@ type validation struct {
result []error
request *http.Request
route *MatchedRoute
bound map[string]interface{}
bound map[string]any
}
// ContentType validates the content type of a request
@ -42,14 +41,14 @@ func validateContentType(allowed []string, actual string) error {
if err != nil {
return errors.InvalidContentType(actual, allowed)
}
if swag.ContainsStringsCI(allowed, mt) {
if stringutils.ContainsStringsCI(allowed, mt) {
return nil
}
if swag.ContainsStringsCI(allowed, "*/*") {
if stringutils.ContainsStringsCI(allowed, "*/*") {
return nil
}
parts := strings.Split(actual, "/")
if len(parts) == 2 && swag.ContainsStringsCI(allowed, parts[0]+"/*") {
if len(parts) == 2 && stringutils.ContainsStringsCI(allowed, parts[0]+"/*") {
return nil
}
return errors.InvalidContentType(actual, allowed)
@ -60,7 +59,7 @@ func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *
context: ctx,
request: request,
route: route,
bound: make(map[string]interface{}),
bound: make(map[string]any),
}
validate.debugLogf("validating request %s %s", request.Method, request.URL.EscapedPath())
@ -83,7 +82,7 @@ func (v *validation) parameters() {
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.Error() == "validation failure list" {
for _, e := range result.(*errors.Validation).Value.([]interface{}) {
for _, e := range result.(*errors.Validation).Value.([]any) {
v.result = append(v.result, e.(error))
}
return
@ -111,7 +110,7 @@ func (v *validation) contentType() {
if ct != "" && v.route.Consumer == nil {
cons, ok := v.route.Consumers[ct]
if !ok {
v.result = append(v.result, errors.New(500, "no consumer registered for %s", ct))
v.result = append(v.result, errors.New(http.StatusInternalServerError, "no consumer registered for %s", ct))
} else {
v.route.Consumer = cons
}

View file

@ -22,7 +22,7 @@ import (
"net/http"
"strings"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/stringutils"
)
// CanHaveBody returns true if this method can have a body
@ -50,7 +50,7 @@ func HasBody(r *http.Request) bool {
return true
}
if r.Header.Get("content-length") != "" {
if r.Header.Get("Content-Length") != "" {
// in this case, no Transfer-Encoding should be present
// we have a header set but it was explicitly set to 0, so we assume no body
return false
@ -145,5 +145,5 @@ func ReadSingleValue(values Gettable, name string) string {
// ReadCollectionValue reads a collection value from a string data source
func ReadCollectionValue(values Gettable, name, collectionFormat string) []string {
v := ReadSingleValue(values, name)
return swag.SplitByFormat(v, collectionFormat)
return stringutils.SplitByFormat(v, collectionFormat)
}

View file

@ -31,7 +31,7 @@ const (
)
// HttpAuthenticator is a function that authenticates a HTTP request
func HttpAuthenticator(handler func(*http.Request) (bool, interface{}, error)) runtime.Authenticator { //nolint:revive,stylecheck
func HttpAuthenticator(handler func(*http.Request) (bool, interface{}, error)) runtime.Authenticator { //nolint:revive
return runtime.AuthenticatorFunc(func(params interface{}) (bool, interface{}, error) {
if request, ok := params.(*http.Request); ok {
return handler(request)
@ -159,7 +159,7 @@ func APIKeyAuth(name, in string, authenticate TokenAuthentication) runtime.Authe
inl := strings.ToLower(in)
if inl != query && inl != header {
// 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(http.StatusInternalServerError, "api key auth: in value needs to be either \"query\" or \"header\""))
}
var getToken func(*http.Request) string
@ -187,7 +187,7 @@ func APIKeyAuthCtx(name, in string, authenticate TokenAuthenticationCtx) runtime
inl := strings.ToLower(in)
if inl != query && inl != header {
// 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(http.StatusInternalServerError, "api key auth: in value needs to be either \"query\" or \"header\""))
}
var getToken func(*http.Request) string

View file

@ -22,7 +22,7 @@ import (
"io"
"reflect"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// TextConsumer creates a new text consumer
@ -99,7 +99,7 @@ func TextProducer() Producer {
v := reflect.Indirect(reflect.ValueOf(data))
if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice {
b, err := swag.WriteJSON(data)
b, err := jsonutils.WriteJSON(data)
if err != nil {
return err
}

View file

@ -18,12 +18,12 @@ import (
"io"
"github.com/go-openapi/runtime"
"gopkg.in/yaml.v3"
yaml "go.yaml.in/yaml/v3"
)
// YAMLConsumer creates a consumer for yaml data
func YAMLConsumer() runtime.Consumer {
return runtime.ConsumerFunc(func(r io.Reader, v interface{}) error {
return runtime.ConsumerFunc(func(r io.Reader, v any) error {
dec := yaml.NewDecoder(r)
return dec.Decode(v)
})
@ -31,7 +31,7 @@ func YAMLConsumer() runtime.Consumer {
// YAMLProducer creates a producer for yaml data
func YAMLProducer() runtime.Producer {
return runtime.ProducerFunc(func(w io.Writer, v interface{}) error {
return runtime.ProducerFunc(func(w io.Writer, v any) error {
enc := yaml.NewEncoder(w)
defer enc.Close()
return enc.Encode(v)

View file

@ -1,61 +1,75 @@
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
version: "2"
linters:
enable-all: true
default: all
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
- cyclop
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- errorlint
- exhaustruct
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase
- funlen
- gochecknoglobals
- gochecknoinits
- gocognit
- godot
- godox
- gosmopolitan
- inamedparam
#- intrange # disabled while < go1.22
- ireturn
- lll
- musttag
- nestif
- nlreturn
- nonamedreturns
- noinlineerr
- paralleltest
- recvcheck
- testpackage
- thelper
- tparallel
- unparam
- varnamelen
- whitespace
- wrapcheck
- wsl
- wsl_v5
settings:
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
gocyclo:
min-complexity: 45
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
# Maximum issues count per one linter.
# Set to 0 to disable.
# Default: 50
max-issues-per-linter: 0
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 0

View file

@ -17,7 +17,7 @@ package spec
import (
"encoding/json"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// ContactInfo contact information for the exposed API.
@ -53,5 +53,5 @@ func (c ContactInfo) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
return jsonutils.ConcatJSON(b1, b2), nil
}

View file

@ -16,4 +16,7 @@ var (
// ErrExpandUnsupportedType indicates that $ref expansion is attempted on some invalid type
ErrExpandUnsupportedType = errors.New("expand: unsupported type. Input should be of type *Parameter or *Response")
// ErrSpec is an error raised by the spec package
ErrSpec = errors.New("spec error")
)

View file

@ -19,6 +19,8 @@ import (
"fmt"
)
const smallPrealloc = 10
// ExpandOptions provides options for the spec expander.
//
// RelativeBase is the path to the root document. This can be a remote URL or a path to a local file.
@ -56,7 +58,7 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error {
if !options.SkipSchemas {
for key, definition := range spec.Definitions {
parentRefs := make([]string, 0, 10)
parentRefs := make([]string, 0, smallPrealloc)
parentRefs = append(parentRefs, "#/definitions/"+key)
def, err := expandSchema(definition, parentRefs, resolver, specBasePath)
@ -160,7 +162,7 @@ func ExpandSchemaWithBasePath(schema *Schema, cache ResolutionCache, opts *Expan
resolver := defaultSchemaLoader(nil, opts, cache, nil)
parentRefs := make([]string, 0, 10)
parentRefs := make([]string, 0, smallPrealloc)
s, err := expandSchema(*schema, parentRefs, resolver, opts.RelativeBase)
if err != nil {
return err
@ -386,7 +388,7 @@ func expandPathItem(pathItem *PathItem, resolver *schemaLoader, basePath string)
return nil
}
parentRefs := make([]string, 0, 10)
parentRefs := make([]string, 0, smallPrealloc)
if err := resolver.deref(pathItem, parentRefs, basePath); resolver.shouldStopOnError(err) {
return err
}
@ -546,7 +548,7 @@ func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePa
return nil
}
parentRefs := make([]string, 0, 10)
parentRefs := make([]string, 0, smallPrealloc)
if ref != nil {
// dereference this $ref
if err = resolver.deref(input, parentRefs, basePath); resolver.shouldStopOnError(err) {

View file

@ -19,7 +19,7 @@ import (
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
const (
@ -74,14 +74,14 @@ func (h *Header) WithDefault(defaultValue interface{}) *Header {
}
// WithMaxLength sets a max length value
func (h *Header) WithMaxLength(max int64) *Header {
h.MaxLength = &max
func (h *Header) WithMaxLength(maximum int64) *Header {
h.MaxLength = &maximum
return h
}
// WithMinLength sets a min length value
func (h *Header) WithMinLength(min int64) *Header {
h.MinLength = &min
func (h *Header) WithMinLength(minimum int64) *Header {
h.MinLength = &minimum
return h
}
@ -98,15 +98,15 @@ func (h *Header) WithMultipleOf(number float64) *Header {
}
// WithMaximum sets a maximum number value
func (h *Header) WithMaximum(max float64, exclusive bool) *Header {
h.Maximum = &max
func (h *Header) WithMaximum(maximum float64, exclusive bool) *Header {
h.Maximum = &maximum
h.ExclusiveMaximum = exclusive
return h
}
// WithMinimum sets a minimum number value
func (h *Header) WithMinimum(min float64, exclusive bool) *Header {
h.Minimum = &min
func (h *Header) WithMinimum(minimum float64, exclusive bool) *Header {
h.Minimum = &minimum
h.ExclusiveMinimum = exclusive
return h
}
@ -161,7 +161,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2, b3), nil
return jsonutils.ConcatJSON(b1, b2, b3), nil
}
// UnmarshalJSON unmarshals this header from JSON

View file

@ -20,7 +20,7 @@ import (
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// Extensions vendor specific extensions
@ -172,7 +172,7 @@ func (i Info) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
return jsonutils.ConcatJSON(b1, b2), nil
}
// UnmarshalJSON marshal this from JSON

View file

@ -19,7 +19,7 @@ import (
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
const (
@ -97,14 +97,14 @@ func (i *Items) WithDefault(defaultValue interface{}) *Items {
}
// WithMaxLength sets a max length value
func (i *Items) WithMaxLength(max int64) *Items {
i.MaxLength = &max
func (i *Items) WithMaxLength(maximum int64) *Items {
i.MaxLength = &maximum
return i
}
// WithMinLength sets a min length value
func (i *Items) WithMinLength(min int64) *Items {
i.MinLength = &min
func (i *Items) WithMinLength(minimum int64) *Items {
i.MinLength = &minimum
return i
}
@ -121,15 +121,15 @@ func (i *Items) WithMultipleOf(number float64) *Items {
}
// WithMaximum sets a maximum number value
func (i *Items) WithMaximum(max float64, exclusive bool) *Items {
i.Maximum = &max
func (i *Items) WithMaximum(maximum float64, exclusive bool) *Items {
i.Maximum = &maximum
i.ExclusiveMaximum = exclusive
return i
}
// WithMinimum sets a minimum number value
func (i *Items) WithMinimum(min float64, exclusive bool) *Items {
i.Minimum = &min
func (i *Items) WithMinimum(minimum float64, exclusive bool) *Items {
i.Minimum = &minimum
i.ExclusiveMinimum = exclusive
return i
}
@ -213,7 +213,7 @@ func (i Items) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b4, b3, b1, b2), nil
return jsonutils.ConcatJSON(b4, b3, b1, b2), nil
}
// JSONLookup look up a value by the json property name

View file

@ -17,7 +17,7 @@ package spec
import (
"encoding/json"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// License information for the exposed API.
@ -52,5 +52,5 @@ func (l License) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
return jsonutils.ConcatJSON(b1, b2), nil
}

View file

@ -21,12 +21,12 @@ import (
"sort"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
func init() {
gob.Register(map[string]interface{}{})
gob.Register([]interface{}{})
gob.Register(map[string]any{})
gob.Register([]any{})
}
// OperationProps describes an operation
@ -58,19 +58,22 @@ func (op OperationProps) MarshalJSON() ([]byte, error) {
type Alias OperationProps
if op.Security == nil {
return json.Marshal(&struct {
Security []map[string][]string `json:"security,omitempty"`
*Alias
Security []map[string][]string `json:"security,omitempty"`
}{
Security: op.Security,
Alias: (*Alias)(&op),
Security: op.Security,
})
}
return json.Marshal(&struct {
Security []map[string][]string `json:"security"`
*Alias
Security []map[string][]string `json:"security"`
}{
Security: op.Security,
Alias: (*Alias)(&op),
Security: op.Security,
})
}
@ -82,6 +85,14 @@ type Operation struct {
OperationProps
}
// NewOperation creates a new operation instance.
// It expects an ID as parameter but not passing an ID is also valid.
func NewOperation(id string) *Operation {
op := new(Operation)
op.ID = id
return op
}
// SuccessResponse gets a success response model
func (o *Operation) SuccessResponse() (*Response, int, bool) {
if o.Responses == nil {
@ -104,7 +115,7 @@ func (o *Operation) SuccessResponse() (*Response, int, bool) {
}
// JSONLookup look up a value by the json property name
func (o Operation) JSONLookup(token string) (interface{}, error) {
func (o Operation) JSONLookup(token string) (any, error) {
if ex, ok := o.Extensions[token]; ok {
return &ex, nil
}
@ -130,18 +141,10 @@ func (o Operation) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
concated := swag.ConcatJSON(b1, b2)
concated := jsonutils.ConcatJSON(b1, b2)
return concated, nil
}
// NewOperation creates a new operation instance.
// It expects an ID as parameter but not passing an ID is also valid.
func NewOperation(id string) *Operation {
op := new(Operation)
op.ID = id
return op
}
// WithID sets the ID property on this operation, allows for chaining.
func (o *Operation) WithID(id string) *Operation {
o.ID = id

View file

@ -19,7 +19,7 @@ import (
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// QueryParam creates a query parameter
@ -210,14 +210,14 @@ func (p *Parameter) AsRequired() *Parameter {
}
// WithMaxLength sets a max length value
func (p *Parameter) WithMaxLength(max int64) *Parameter {
p.MaxLength = &max
func (p *Parameter) WithMaxLength(maximum int64) *Parameter {
p.MaxLength = &maximum
return p
}
// WithMinLength sets a min length value
func (p *Parameter) WithMinLength(min int64) *Parameter {
p.MinLength = &min
func (p *Parameter) WithMinLength(minimum int64) *Parameter {
p.MinLength = &minimum
return p
}
@ -234,15 +234,15 @@ func (p *Parameter) WithMultipleOf(number float64) *Parameter {
}
// WithMaximum sets a maximum number value
func (p *Parameter) WithMaximum(max float64, exclusive bool) *Parameter {
p.Maximum = &max
func (p *Parameter) WithMaximum(maximum float64, exclusive bool) *Parameter {
p.Maximum = &maximum
p.ExclusiveMaximum = exclusive
return p
}
// WithMinimum sets a minimum number value
func (p *Parameter) WithMinimum(min float64, exclusive bool) *Parameter {
p.Minimum = &min
func (p *Parameter) WithMinimum(minimum float64, exclusive bool) *Parameter {
p.Minimum = &minimum
p.ExclusiveMinimum = exclusive
return p
}
@ -322,5 +322,5 @@ func (p Parameter) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b3, b1, b2, b4, b5), nil
return jsonutils.ConcatJSON(b3, b1, b2, b4, b5), nil
}

View file

@ -18,7 +18,7 @@ import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// PathItemProps the path item specific properties
@ -82,6 +82,6 @@ func (p PathItem) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
concated := swag.ConcatJSON(b3, b4, b5)
concated := jsonutils.ConcatJSON(b3, b4, b5)
return concated, nil
}

View file

@ -19,7 +19,7 @@ import (
"fmt"
"strings"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// Paths holds the relative paths to the individual endpoints.
@ -30,18 +30,19 @@ import (
// For more information: http://goo.gl/8us55a#pathsObject
type Paths struct {
VendorExtensible
Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/"
}
// JSONLookup look up a value by the json property name
func (p Paths) JSONLookup(token string) (interface{}, error) {
func (p Paths) JSONLookup(token string) (any, error) {
if pi, ok := p.Paths[token]; ok {
return &pi, nil
}
if ex, ok := p.Extensions[token]; ok {
return &ex, nil
}
return nil, fmt.Errorf("object has no field %q", token)
return nil, fmt.Errorf("object has no field %q: %w", token, ErrSpec)
}
// UnmarshalJSON hydrates this items instance with the data from JSON
@ -53,9 +54,9 @@ func (p *Paths) UnmarshalJSON(data []byte) error {
for k, v := range res {
if strings.HasPrefix(strings.ToLower(k), "x-") {
if p.Extensions == nil {
p.Extensions = make(map[string]interface{})
p.Extensions = make(map[string]any)
}
var d interface{}
var d any
if err := json.Unmarshal(v, &d); err != nil {
return err
}
@ -92,6 +93,6 @@ func (p Paths) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
concated := swag.ConcatJSON(b1, b2)
concated := jsonutils.ConcatJSON(b1, b2)
return concated, nil
}

View file

@ -9,8 +9,9 @@ import (
// OrderSchemaItem holds a named schema (e.g. from a property of an object)
type OrderSchemaItem struct {
Name string
Schema
Name string
}
// OrderSchemaItems is a sortable slice of named schemas.

View file

@ -45,6 +45,23 @@ type Ref struct {
jsonreference.Ref
}
// NewRef creates a new instance of a ref object
// returns an error when the reference uri is an invalid uri
func NewRef(refURI string) (Ref, error) {
ref, err := jsonreference.New(refURI)
if err != nil {
return Ref{}, err
}
return Ref{Ref: ref}, nil
}
// MustCreateRef creates a ref object but panics when refURI is invalid.
// Use the NewRef method for a version that returns an error.
func MustCreateRef(refURI string) Ref {
return Ref{Ref: jsonreference.MustCreateRef(refURI)}
}
// RemoteURI gets the remote uri part of the ref
func (r *Ref) RemoteURI() string {
if r.String() == "" {
@ -75,10 +92,11 @@ func (r *Ref) IsValidURI(basepaths ...string) bool {
}
defer rr.Body.Close()
return rr.StatusCode/100 == 2
// true if the response is >= 200 and < 300
return rr.StatusCode/100 == 2 //nolint:mnd
}
if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) {
if !r.HasFileScheme && !r.HasFullFilePath && !r.HasURLPathOnly {
return false
}
@ -114,22 +132,6 @@ func (r *Ref) Inherits(child Ref) (*Ref, error) {
return &Ref{Ref: *ref}, nil
}
// NewRef creates a new instance of a ref object
// returns an error when the reference uri is an invalid uri
func NewRef(refURI string) (Ref, error) {
ref, err := jsonreference.New(refURI)
if err != nil {
return Ref{}, err
}
return Ref{Ref: ref}, nil
}
// MustCreateRef creates a ref object but panics when refURI is invalid.
// Use the NewRef method for a version that returns an error.
func MustCreateRef(refURI string) Ref {
return Ref{Ref: jsonreference.MustCreateRef(refURI)}
}
// MarshalJSON marshals this ref into a JSON object
func (r Ref) MarshalJSON() ([]byte, error) {
str := r.String()
@ -139,13 +141,13 @@ func (r Ref) MarshalJSON() ([]byte, error) {
}
return []byte("{}"), nil
}
v := map[string]interface{}{"$ref": str}
v := map[string]any{"$ref": str}
return json.Marshal(v)
}
// UnmarshalJSON unmarshals this ref from a JSON object
func (r *Ref) UnmarshalJSON(d []byte) error {
var v map[string]interface{}
var v map[string]any
if err := json.Unmarshal(d, &v); err != nil {
return err
}
@ -174,7 +176,7 @@ func (r *Ref) GobDecode(b []byte) error {
return json.Unmarshal(raw, r)
}
func (r *Ref) fromMap(v map[string]interface{}) error {
func (r *Ref) fromMap(v map[string]any) error {
if v == nil {
return nil
}

View file

@ -3,7 +3,7 @@ package spec
import (
"fmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
func resolveAnyWithBase(root interface{}, ref *Ref, result interface{}, options *ExpandOptions) error {
@ -45,7 +45,7 @@ func ResolveRef(root interface{}, ref *Ref) (*Schema, error) {
return sch, nil
case map[string]interface{}:
newSch := new(Schema)
if err = swag.DynamicJSONToStruct(sch, newSch); err != nil {
if err = jsonutils.FromDynamicJSON(sch, newSch); err != nil {
return nil, err
}
return newSch, nil

View file

@ -18,7 +18,7 @@ import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// ResponseProps properties specific to a response
@ -38,6 +38,18 @@ type Response struct {
VendorExtensible
}
// NewResponse creates a new response instance
func NewResponse() *Response {
return new(Response)
}
// ResponseRef creates a response as a json reference
func ResponseRef(url string) *Response {
resp := NewResponse()
resp.Ref = MustCreateRef(url)
return resp
}
// JSONLookup look up a value by the json property name
func (r Response) JSONLookup(token string) (interface{}, error) {
if ex, ok := r.Extensions[token]; ok {
@ -79,9 +91,9 @@ func (r Response) MarshalJSON() ([]byte, error) {
Headers map[string]Header `json:"headers,omitempty"`
Examples map[string]interface{} `json:"examples,omitempty"`
}{
Description: r.ResponseProps.Description,
Schema: r.ResponseProps.Schema,
Examples: r.ResponseProps.Examples,
Description: r.Description,
Schema: r.Schema,
Examples: r.Examples,
})
}
if err != nil {
@ -96,19 +108,7 @@ func (r Response) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2, b3), nil
}
// NewResponse creates a new response instance
func NewResponse() *Response {
return new(Response)
}
// ResponseRef creates a response as a json reference
func ResponseRef(url string) *Response {
resp := NewResponse()
resp.Ref = MustCreateRef(url)
return resp
return jsonutils.ConcatJSON(b1, b2, b3), nil
}
// WithDescription sets the description on this response, allows for chaining

View file

@ -21,7 +21,7 @@ import (
"strconv"
"strings"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// Responses is a container for the expected responses of an operation.
@ -55,7 +55,7 @@ func (r Responses) JSONLookup(token string) (interface{}, error) {
return scr, nil
}
}
return nil, fmt.Errorf("object has no field %q", token)
return nil, fmt.Errorf("object has no field %q: %w", token, ErrSpec)
}
// UnmarshalJSON hydrates this items instance with the data from JSON
@ -83,7 +83,7 @@ func (r Responses) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
concated := swag.ConcatJSON(b1, b2)
concated := jsonutils.ConcatJSON(b1, b2)
return concated, nil
}

View file

@ -20,7 +20,8 @@ import (
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonname"
"github.com/go-openapi/swag/jsonutils"
)
// BooleanProperty creates a boolean property
@ -125,20 +126,20 @@ func (r SchemaURL) MarshalJSON() ([]byte, error) {
if r == "" {
return []byte("{}"), nil
}
v := map[string]interface{}{"$schema": string(r)}
v := map[string]any{"$schema": string(r)}
return json.Marshal(v)
}
// UnmarshalJSON unmarshal this from JSON
func (r *SchemaURL) UnmarshalJSON(data []byte) error {
var v map[string]interface{}
var v map[string]any
if err := json.Unmarshal(data, &v); err != nil {
return err
}
return r.fromMap(v)
}
func (r *SchemaURL) fromMap(v map[string]interface{}) error {
func (r *SchemaURL) fromMap(v map[string]any) error {
if v == nil {
return nil
}
@ -165,7 +166,7 @@ type SchemaProps struct {
Nullable bool `json:"nullable,omitempty"`
Format string `json:"format,omitempty"`
Title string `json:"title,omitempty"`
Default interface{} `json:"default,omitempty"`
Default any `json:"default,omitempty"`
Maximum *float64 `json:"maximum,omitempty"`
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
Minimum *float64 `json:"minimum,omitempty"`
@ -177,7 +178,7 @@ type SchemaProps struct {
MinItems *int64 `json:"minItems,omitempty"`
UniqueItems bool `json:"uniqueItems,omitempty"`
MultipleOf *float64 `json:"multipleOf,omitempty"`
Enum []interface{} `json:"enum,omitempty"`
Enum []any `json:"enum,omitempty"`
MaxProperties *int64 `json:"maxProperties,omitempty"`
MinProperties *int64 `json:"minProperties,omitempty"`
Required []string `json:"required,omitempty"`
@ -200,7 +201,7 @@ type SwaggerSchemaProps struct {
ReadOnly bool `json:"readOnly,omitempty"`
XML *XMLObject `json:"xml,omitempty"`
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
Example interface{} `json:"example,omitempty"`
Example any `json:"example,omitempty"`
}
// Schema the schema object allows the definition of input and output data types.
@ -214,11 +215,12 @@ type Schema struct {
VendorExtensible
SchemaProps
SwaggerSchemaProps
ExtraProps map[string]interface{} `json:"-"`
ExtraProps map[string]any `json:"-"`
}
// JSONLookup implements an interface to customize json pointer lookup
func (s Schema) JSONLookup(token string) (interface{}, error) {
func (s Schema) JSONLookup(token string) (any, error) {
if ex, ok := s.Extensions[token]; ok {
return &ex, nil
}
@ -275,14 +277,14 @@ func (s *Schema) WithAllOf(schemas ...Schema) *Schema {
}
// WithMaxProperties sets the max number of properties an object can have
func (s *Schema) WithMaxProperties(max int64) *Schema {
s.MaxProperties = &max
func (s *Schema) WithMaxProperties(maximum int64) *Schema {
s.MaxProperties = &maximum
return s
}
// WithMinProperties sets the min number of properties an object must have
func (s *Schema) WithMinProperties(min int64) *Schema {
s.MinProperties = &min
func (s *Schema) WithMinProperties(minimum int64) *Schema {
s.MinProperties = &minimum
return s
}
@ -316,7 +318,7 @@ func (s *Schema) CollectionOf(items Schema) *Schema {
}
// WithDefault sets the default value on this parameter
func (s *Schema) WithDefault(defaultValue interface{}) *Schema {
func (s *Schema) WithDefault(defaultValue any) *Schema {
s.Default = defaultValue
return s
}
@ -334,14 +336,14 @@ func (s *Schema) AddRequired(items ...string) *Schema {
}
// WithMaxLength sets a max length value
func (s *Schema) WithMaxLength(max int64) *Schema {
s.MaxLength = &max
func (s *Schema) WithMaxLength(maximum int64) *Schema {
s.MaxLength = &maximum
return s
}
// WithMinLength sets a min length value
func (s *Schema) WithMinLength(min int64) *Schema {
s.MinLength = &min
func (s *Schema) WithMinLength(minimum int64) *Schema {
s.MinLength = &minimum
return s
}
@ -358,22 +360,22 @@ func (s *Schema) WithMultipleOf(number float64) *Schema {
}
// WithMaximum sets a maximum number value
func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema {
s.Maximum = &max
func (s *Schema) WithMaximum(maximum float64, exclusive bool) *Schema {
s.Maximum = &maximum
s.ExclusiveMaximum = exclusive
return s
}
// WithMinimum sets a minimum number value
func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema {
s.Minimum = &min
func (s *Schema) WithMinimum(minimum float64, exclusive bool) *Schema {
s.Minimum = &minimum
s.ExclusiveMinimum = exclusive
return s
}
// WithEnum sets a the enum values (replace)
func (s *Schema) WithEnum(values ...interface{}) *Schema {
s.Enum = append([]interface{}{}, values...)
func (s *Schema) WithEnum(values ...any) *Schema {
s.Enum = append([]any{}, values...)
return s
}
@ -426,7 +428,7 @@ func (s *Schema) AsWritable() *Schema {
}
// WithExample sets the example for this schema
func (s *Schema) WithExample(example interface{}) *Schema {
func (s *Schema) WithExample(example any) *Schema {
s.Example = example
return s
}
@ -566,33 +568,33 @@ func (s Schema) Validations() SchemaValidations {
func (s Schema) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(s.SchemaProps)
if err != nil {
return nil, fmt.Errorf("schema props %v", err)
return nil, fmt.Errorf("schema props %v: %w", err, ErrSpec)
}
b2, err := json.Marshal(s.VendorExtensible)
if err != nil {
return nil, fmt.Errorf("vendor props %v", err)
return nil, fmt.Errorf("vendor props %v: %w", err, ErrSpec)
}
b3, err := s.Ref.MarshalJSON()
if err != nil {
return nil, fmt.Errorf("ref prop %v", err)
return nil, fmt.Errorf("ref prop %v: %w", err, ErrSpec)
}
b4, err := s.Schema.MarshalJSON()
if err != nil {
return nil, fmt.Errorf("schema prop %v", err)
return nil, fmt.Errorf("schema prop %v: %w", err, ErrSpec)
}
b5, err := json.Marshal(s.SwaggerSchemaProps)
if err != nil {
return nil, fmt.Errorf("common validations %v", err)
return nil, fmt.Errorf("common validations %v: %w", err, ErrSpec)
}
var b6 []byte
if s.ExtraProps != nil {
jj, err := json.Marshal(s.ExtraProps)
if err != nil {
return nil, fmt.Errorf("extra props %v", err)
return nil, fmt.Errorf("extra props %v: %w", err, ErrSpec)
}
b6 = jj
}
return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil
return jsonutils.ConcatJSON(b1, b2, b3, b4, b5, b6), nil
}
// UnmarshalJSON marshal this from JSON
@ -610,7 +612,7 @@ func (s *Schema) UnmarshalJSON(data []byte) error {
SwaggerSchemaProps: props.SwaggerSchemaProps,
}
var d map[string]interface{}
var d map[string]any
if err := json.Unmarshal(data, &d); err != nil {
return err
}
@ -620,7 +622,7 @@ func (s *Schema) UnmarshalJSON(data []byte) error {
delete(d, "$ref")
delete(d, "$schema")
for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
for _, pn := range jsonname.DefaultJSONNameProvider.GetJSONNames(s) {
delete(d, pn)
}
@ -628,13 +630,13 @@ func (s *Schema) UnmarshalJSON(data []byte) error {
lk := strings.ToLower(k)
if strings.HasPrefix(lk, "x-") {
if sch.Extensions == nil {
sch.Extensions = map[string]interface{}{}
sch.Extensions = map[string]any{}
}
sch.Extensions[k] = vv
continue
}
if sch.ExtraProps == nil {
sch.ExtraProps = map[string]interface{}{}
sch.ExtraProps = map[string]any{}
}
sch.ExtraProps[k] = vv
}

View file

@ -22,7 +22,9 @@ import (
"reflect"
"strings"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
"github.com/go-openapi/swag/loading"
"github.com/go-openapi/swag/stringutils"
)
// PathLoader is a function to use when loading remote refs.
@ -34,7 +36,7 @@ import (
// this value with its own default (a loader to retrieve YAML documents as
// well as JSON ones).
var PathLoader = func(pth string) (json.RawMessage, error) {
data, err := swag.LoadFromFileOrHTTP(pth)
data, err := loading.LoadFromFileOrHTTP(pth)
if err != nil {
return nil, err
}
@ -73,12 +75,23 @@ func newResolverContext(options *ExpandOptions) *resolverContext {
}
type schemaLoader struct {
root interface{}
root any
options *ExpandOptions
cache ResolutionCache
context *resolverContext
}
// Resolve resolves a reference against basePath and stores the result in target.
//
// Resolve is not in charge of following references: it only resolves ref by following its URL.
//
// If the schema the ref is referring to holds nested refs, Resolve doesn't resolve them.
//
// If basePath is an empty string, ref is resolved against the root schema stored in the schemaLoader struct
func (r *schemaLoader) Resolve(ref *Ref, target any, basePath string) error {
return r.resolveRef(ref, target, basePath)
}
func (r *schemaLoader) transitiveResolver(basePath string, ref Ref) *schemaLoader {
if ref.IsRoot() || ref.HasFragmentOnly {
return r
@ -113,7 +126,7 @@ func (r *schemaLoader) updateBasePath(transitive *schemaLoader, basePath string)
return basePath
}
func (r *schemaLoader) resolveRef(ref *Ref, target interface{}, basePath string) error {
func (r *schemaLoader) resolveRef(ref *Ref, target any, basePath string) error {
tgt := reflect.ValueOf(target)
if tgt.Kind() != reflect.Ptr {
return ErrResolveRefNeedsAPointer
@ -124,8 +137,8 @@ func (r *schemaLoader) resolveRef(ref *Ref, target interface{}, basePath string)
}
var (
res interface{}
data interface{}
res any
data any
err error
)
@ -155,10 +168,10 @@ func (r *schemaLoader) resolveRef(ref *Ref, target interface{}, basePath string)
return err
}
}
return swag.DynamicJSONToStruct(res, target)
return jsonutils.FromDynamicJSON(res, target)
}
func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error) {
func (r *schemaLoader) load(refURL *url.URL) (any, url.URL, bool, error) {
debugLog("loading schema from url: %s", refURL)
toFetch := *refURL
toFetch.Fragment = ""
@ -178,7 +191,7 @@ func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error)
return nil, url.URL{}, false, err
}
var doc interface{}
var doc any
if err := json.Unmarshal(b, &doc); err != nil {
return nil, url.URL{}, false, err
}
@ -197,25 +210,14 @@ func (r *schemaLoader) isCircular(ref *Ref, basePath string, parentRefs ...strin
foundCycle = true
return
}
foundCycle = swag.ContainsStrings(parentRefs, normalizedRef) // normalized windows url's are lower cased
foundCycle = stringutils.ContainsStrings(parentRefs, normalizedRef) // normalized windows url's are lower cased
if foundCycle {
r.context.circulars[normalizedRef] = true
}
return
}
// Resolve resolves a reference against basePath and stores the result in target.
//
// Resolve is not in charge of following references: it only resolves ref by following its URL.
//
// If the schema the ref is referring to holds nested refs, Resolve doesn't resolve them.
//
// If basePath is an empty string, ref is resolved against the root schema stored in the schemaLoader struct
func (r *schemaLoader) Resolve(ref *Ref, target interface{}, basePath string) error {
return r.resolveRef(ref, target, basePath)
}
func (r *schemaLoader) deref(input interface{}, parentRefs []string, basePath string) error {
func (r *schemaLoader) deref(input any, parentRefs []string, basePath string) error {
var ref *Ref
switch refable := input.(type) {
case *Schema:
@ -267,7 +269,7 @@ func (r *schemaLoader) shouldStopOnError(err error) bool {
return false
}
func (r *schemaLoader) setSchemaID(target interface{}, id, basePath string) (string, string) {
func (r *schemaLoader) setSchemaID(target any, id, basePath string) (string, string) {
debugLog("schema has ID: %s", id)
// handling the case when id is a folder
@ -299,7 +301,7 @@ func (r *schemaLoader) setSchemaID(target interface{}, id, basePath string) (str
}
func defaultSchemaLoader(
root interface{},
root any,
expandOptions *ExpandOptions,
cache ResolutionCache,
context *resolverContext) *schemaLoader {

View file

@ -18,7 +18,7 @@ import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
const (
@ -158,7 +158,7 @@ func (s SecurityScheme) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
return jsonutils.ConcatJSON(b1, b2), nil
}
// UnmarshalJSON marshal this from JSON

View file

@ -22,7 +22,7 @@ import (
"strconv"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// Swagger this is the root document object for the API specification.
@ -54,7 +54,7 @@ func (s Swagger) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
return jsonutils.ConcatJSON(b1, b2), nil
}
// UnmarshalJSON unmarshals a swagger spec from json
@ -379,7 +379,7 @@ func (s *StringOrArray) UnmarshalJSON(data []byte) error {
*s = StringOrArray([]string{v})
return nil
default:
return fmt.Errorf("only string or array is allowed, not %T", single)
return fmt.Errorf("only string or array is allowed, not %T: %w", single, ErrSpec)
}
}

View file

@ -18,7 +18,7 @@ import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonutils"
)
// TagProps describe a tag entry in the top level tags section of a swagger spec
@ -28,11 +28,6 @@ type TagProps struct {
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
}
// NewTag creates a new tag
func NewTag(name, description string, externalDocs *ExternalDocumentation) Tag {
return Tag{TagProps: TagProps{Description: description, Name: name, ExternalDocs: externalDocs}}
}
// Tag allows adding meta data to a single tag that is used by the
// [Operation Object](http://goo.gl/8us55a#operationObject).
// It is not mandatory to have a Tag Object per tag used there.
@ -43,6 +38,11 @@ type Tag struct {
TagProps
}
// NewTag creates a new tag
func NewTag(name, description string, externalDocs *ExternalDocumentation) Tag {
return Tag{TagProps: TagProps{Description: description, Name: name, ExternalDocs: externalDocs}}
}
// JSONLookup implements an interface to customize json pointer lookup
func (t Tag) JSONLookup(token string) (interface{}, error) {
if ex, ok := t.Extensions[token]; ok {
@ -63,7 +63,7 @@ func (t Tag) MarshalJSON() ([]byte, error) {
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
return jsonutils.ConcatJSON(b1, b2), nil
}
// UnmarshalJSON marshal this from JSON

View file

@ -54,7 +54,8 @@ func (c clearedValidations) apply(cbs []func(string, interface{})) {
//
// Some callbacks may be set by the caller to capture changed values.
func (v *CommonValidations) ClearNumberValidations(cbs ...func(string, interface{})) {
done := make(clearedValidations, 0, 5)
const maxNumberValidations = 5
done := make(clearedValidations, 0, maxNumberValidations)
defer func() {
done.apply(cbs)
}()
@ -85,7 +86,8 @@ func (v *CommonValidations) ClearNumberValidations(cbs ...func(string, interface
//
// Some callbacks may be set by the caller to capture changed values.
func (v *CommonValidations) ClearStringValidations(cbs ...func(string, interface{})) {
done := make(clearedValidations, 0, 3)
const maxStringValidations = 3
done := make(clearedValidations, 0, maxStringValidations)
defer func() {
done.apply(cbs)
}()
@ -108,7 +110,8 @@ func (v *CommonValidations) ClearStringValidations(cbs ...func(string, interface
//
// Some callbacks may be set by the caller to capture changed values.
func (v *CommonValidations) ClearArrayValidations(cbs ...func(string, interface{})) {
done := make(clearedValidations, 0, 3)
const maxArrayValidations = 3
done := make(clearedValidations, 0, maxArrayValidations)
defer func() {
done.apply(cbs)
}()
@ -195,7 +198,8 @@ func (v SchemaValidations) Validations() SchemaValidations {
//
// Some callbacks may be set by the caller to capture changed values.
func (v *SchemaValidations) ClearObjectValidations(cbs ...func(string, interface{})) {
done := make(clearedValidations, 0, 3)
const maxObjectValidations = 3
done := make(clearedValidations, 0, maxObjectValidations)
defer func() {
done.apply(cbs)
}()

View file

@ -1,61 +1,75 @@
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
version: "2"
linters:
enable-all: true
default: all
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
- cyclop
- depguard
- errchkjson
- inamedparam
- nonamedreturns
- musttag
- ireturn
- errorlint
- exhaustruct
- forcetypeassert
- cyclop
# deprecated linters
- deadcode
- interfacer
- scopelint
- varcheck
- structcheck
- golint
- nosnakecase
- funlen
- gochecknoglobals
- gochecknoinits
- gocognit
- godot
- godox
- gosmopolitan
- inamedparam
#- intrange # disabled while < go1.22
- ireturn
- lll
- musttag
- nestif
- nlreturn
- nonamedreturns
- noinlineerr
- paralleltest
- recvcheck
- testpackage
- thelper
- tparallel
- unparam
- varnamelen
- whitespace
- wrapcheck
- wsl
- wsl_v5
settings:
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
gocyclo:
min-complexity: 45
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
# Maximum issues count per one linter.
# Set to 0 to disable.
# Default: 50
max-issues-per-linter: 0
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 0

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)
//
// swagger:strfmt bsonobjectid
type ObjectId bsonprim.ObjectID //nolint:revive,stylecheck
type ObjectId bsonprim.ObjectID //nolint:revive
// NewObjectId creates a ObjectId from a Hex String
func NewObjectId(hex string) ObjectId { //nolint:revive,stylecheck
func NewObjectId(hex string) ObjectId { //nolint:revive
oid, err := bsonprim.ObjectIDFromHex(hex)
if err != nil {
panic(err)
@ -83,7 +83,7 @@ func (id *ObjectId) Scan(raw interface{}) error {
case string:
data = []byte(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.URI from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.URI from: %#v: %w", v, ErrFormat)
}
return id.UnmarshalText(data)

View file

@ -17,7 +17,6 @@ package strfmt
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"time"
@ -84,7 +83,7 @@ func (d *Date) Scan(raw interface{}) error {
*d = Date{}
return nil
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Date from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.Date from: %#v: %w", v, ErrFormat)
}
}
@ -134,7 +133,7 @@ func (d *Date) UnmarshalBSON(data []byte) error {
return nil
}
return errors.New("couldn't unmarshal bson bytes value as Date")
return fmt.Errorf("couldn't unmarshal bson bytes value as Date: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.

View file

@ -18,46 +18,23 @@ import (
"database/sql/driver"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/mail"
"regexp"
"net/netip"
"strconv"
"strings"
"github.com/asaskevich/govalidator"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
"golang.org/x/net/idna"
)
const (
// HostnamePattern http://json-schema.org/latest/json-schema-validation.html#anchor114
// A string instance is valid against this attribute if it is a valid
// representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
// http://tools.ietf.org/html/rfc1034#section-3.5
// <digit> ::= any one of the ten digits 0 through 9
// var digit = /[0-9]/;
// <letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
// var letter = /[a-zA-Z]/;
// <let-dig> ::= <letter> | <digit>
// var letDig = /[0-9a-zA-Z]/;
// <let-dig-hyp> ::= <let-dig> | "-"
// var letDigHyp = /[-0-9a-zA-Z]/;
// <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
// var ldhStr = /[-0-9a-zA-Z]+/;
// <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
// var label = /[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?/;
// <subdomain> ::= <label> | <subdomain> "." <label>
// var subdomain = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/;
// <domain> ::= <subdomain> | " "
// HostnamePattern http://json-schema.org/latest/json-schema-validation.html#anchor114.
//
// Additional validations:
// - for FDQNs, top-level domain (e.g. ".com"), is at least to letters long (no special characters here)
// - hostnames may start with a digit [RFC1123]
// - special registered names with an underscore ('_') are not allowed in this context
// - dashes are permitted, but not at the start or the end of a segment
// - long top-level domain names (e.g. example.london) are permitted
// - 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})$`
// Deprecated: this package no longer uses regular expressions to validate hostnames.
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-Z0-9-\p{L}]){2,63})$`
// json null type
jsonNull = "null"
@ -85,30 +62,254 @@ const (
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 (
rxHostname = regexp.MustCompile(HostnamePattern)
var idnaHostChecker = idna.New(
idna.ValidateForRegistration(), // shorthand for [idna.StrictDomainName], [idna.ValidateLabels], [idna.VerifyDNSLength], [idna.BidiRule]
)
// IsHostname returns true when the string is a valid hostname
// IsHostname returns true when the string is a valid hostname.
//
// It follows the rules detailed at https://url.spec.whatwg.org/#concept-host-parser
// and implemented by most modern web browsers.
//
// It supports IDNA rules regarding internationalized names with unicode.
//
// Besides:
// * the empty string is not a valid host name
// * a trailing dot is allowed in names and IPv4's (not IPv6)
// * a host name can be a valid IPv4 (with decimal, octal or hexadecimal numbers) or IPv6 address
// * IPv6 zones are disallowed
// * top-level domains can be unicode (cf. https://www.iana.org/domains/root/db).
//
// NOTE: this validator doesn't check top-level domains against the IANA root database.
// It merely ensures that a top-level domain in a FQDN is at least 2 code points long.
func IsHostname(str string) bool {
if !rxHostname.MatchString(str) {
if len(str) == 0 {
return false
}
// the sum of all label octets and label lengths is limited to 255.
if len(str) > 255 {
// IP v6 check
if ipv6Cleaned, found := strings.CutPrefix(str, "["); found {
ipv6Cleaned, found = strings.CutSuffix(ipv6Cleaned, "]")
if !found {
return false
}
return isValidIPv6(ipv6Cleaned)
}
// IDNA check
res, err := idnaHostChecker.ToASCII(strings.ToLower(str))
if err != nil || res == "" {
return false
}
// Each node has a label, which is zero to 63 octets in length
parts := strings.Split(str, ".")
valid := true
for _, p := range parts {
if len(p) > 63 {
valid = false
parts := strings.Split(res, ".")
// IP v4 check
lastPart, lastIndex, shouldBeIPv4 := domainEndsAsNumber(parts)
if shouldBeIPv4 {
// domain ends in a number: must be an IPv4
return isValidIPv4(parts[:lastIndex+1]) // if the last part is a trailing dot, remove it
}
// check TLD length (excluding trailing dot)
const minTLDLength = 2
if lastIndex > 0 && len(lastPart) < minTLDLength {
return false
}
return true
}
// domainEndsAsNumber determines if a domain name ends with a decimal, octal or hex digit,
// accounting for a possible trailing dot (the last part being empty in that case).
//
// It returns the last non-trailing dot part and if that part consists only of (dec/hex/oct) digits.
func domainEndsAsNumber(parts []string) (lastPart string, lastIndex int, ok bool) {
// NOTE: using ParseUint(x, 0, 32) is not an option, as the IPv4 format supported why WHATWG
// doesn't support notations such as "0b1001" (binary digits) or "0o666" (alternate notation for octal digits).
lastIndex = len(parts) - 1
lastPart = parts[lastIndex]
if len(lastPart) == 0 {
// trailing dot
if len(parts) == 1 { // dot-only string: normally already ruled out by the IDNA check above
return lastPart, lastIndex, false
}
lastIndex--
lastPart = parts[lastIndex]
}
if startOfHexDigit(lastPart) {
for _, b := range []byte(lastPart[2:]) {
if !isHexDigit(b) {
return lastPart, lastIndex, false
}
}
return lastPart, lastIndex, true
}
// check for decimal and octal
for _, b := range []byte(lastPart) {
if !isASCIIDigit(b) {
return lastPart, lastIndex, false
}
}
return valid
return lastPart, lastIndex, true
}
func startOfHexDigit(str string) bool {
return strings.HasPrefix(str, "0x") // the input has already been lower-cased
}
func startOfOctalDigit(str string) bool {
if str == "0" {
// a single "0" is considered decimal
return false
}
return strings.HasPrefix(str, "0")
}
func isValidIPv6(str string) bool {
// disallow empty ipv6 address
if len(str) == 0 {
return false
}
addr, err := netip.ParseAddr(str)
if err != nil {
return false
}
if !addr.Is6() {
return false
}
// explicit desupport of IPv6 zones
if addr.Zone() != "" {
return false
}
return true
}
// isValidIPv4 parses an IPv4 with deciaml, hex or octal digit parts.
//
// We can't rely on [netip.ParseAddr] because we may get a mix of decimal, octal and hex digits.
//
// Examples of valid addresses not supported by [netip.ParseAddr] or [net.ParseIP]:
//
// "192.0x00A80001"
// "0300.0250.0340.001"
// "1.0x.1.1"
//
// But not:
//
// "0b1010.2.3.4"
// "0o07.2.3.4"
func isValidIPv4(parts []string) bool {
// NOTE: using ParseUint(x, 0, 32) is not an option, even though it would simplify this code a lot.
// The IPv4 format supported why WHATWG doesn't support notations such as "0b1001" (binary digits)
// or "0o666" (alternate notation for octal digits).
const (
maxPartsInIPv4 = 4
maxDigitsInPart = 11 // max size of a 4-bytes hex or octal digit
)
if len(parts) == 0 || len(parts) > maxPartsInIPv4 {
return false
}
// we call this when we know that the last part is a digit part, so len(lastPart)>0
digits := make([]uint64, 0, maxPartsInIPv4)
for _, part := range parts {
if len(part) == 0 { // empty part: this case has normally been already ruled out by the IDNA check above
return false
}
if len(part) > maxDigitsInPart { // whether decimal, octal or hex, an address can't exceed that length
return false
}
if !isASCIIDigit(part[0]) { // start of an IPv4 part is always a digit
return false
}
switch {
case startOfHexDigit(part):
const hexDigitOffset = 2
hexString := part[hexDigitOffset:]
if len(hexString) == 0 { // 0x part: assume 0
digits = append(digits, 0)
continue
}
hexDigit, err := strconv.ParseUint(hexString, 16, 32)
if err != nil {
return false
}
digits = append(digits, hexDigit)
continue
case startOfOctalDigit(part):
const octDigitOffset = 1
octString := part[octDigitOffset:] // we know that this is not empty
octDigit, err := strconv.ParseUint(octString, 8, 32)
if err != nil {
return false
}
digits = append(digits, octDigit)
default: // assume decimal digits (0-255)
// we know that we don't have a leading 0 (would have been caught by octal digit)
decDigit, err := strconv.ParseUint(part, 10, 8)
if err != nil {
return false
}
digits = append(digits, decDigit)
}
}
// now check the digits: the last digit may encompass several parts of the address
lastDigit := digits[len(digits)-1]
if lastDigit > uint64(1)<<uint64(8*(maxPartsInIPv4+1-len(digits))) { //nolint:gosec,mnd // 256^(5 - len(digits)) - safe conversion
return false
}
if len(digits) > 1 {
const maxUint8 = uint64(^uint8(0))
for i := range len(digits) - 2 {
if digits[i] > maxUint8 {
return false
}
}
}
return true
}
func isHexDigit(c byte) bool {
switch {
case '0' <= c && c <= '9':
return true
case 'a' <= c && c <= 'f': // assume the input string to be lower case
return true
}
return false
}
func isASCIIDigit(c byte) bool {
return c >= '0' && c <= '9'
}
// IsUUID returns true is the string matches a UUID (in any version, including v6 and v7), upper case is allowed
@ -117,22 +318,28 @@ func IsUUID(str string) bool {
return err == nil
}
const (
uuidV3 = 3
uuidV4 = 4
uuidV5 = 5
)
// IsUUID3 returns true is the string matches a UUID v3, upper case is allowed
func IsUUID3(str string) bool {
id, err := uuid.Parse(str)
return err == nil && id.Version() == uuid.Version(3)
return err == nil && id.Version() == uuid.Version(uuidV3)
}
// IsUUID4 returns true is the string matches a UUID v4, upper case is allowed
func IsUUID4(str string) bool {
id, err := uuid.Parse(str)
return err == nil && id.Version() == uuid.Version(4)
return err == nil && id.Version() == uuid.Version(uuidV4)
}
// IsUUID5 returns true is the string matches a UUID v5, upper case is allowed
func IsUUID5(str string) bool {
id, err := uuid.Parse(str)
return err == nil && id.Version() == uuid.Version(5)
return err == nil && id.Version() == uuid.Version(uuidV5)
}
// IsEmail validates an email address.
@ -269,7 +476,7 @@ func (b *Base64) Scan(raw interface{}) error {
}
*b = Base64(vv)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Base64 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.Base64 from: %#v: %w", v, ErrFormat)
}
return nil
@ -323,7 +530,7 @@ func (b *Base64) UnmarshalBSON(data []byte) error {
*b = Base64(vb)
return nil
}
return errors.New("couldn't unmarshal bson bytes as base64")
return fmt.Errorf("couldn't unmarshal bson bytes as base64: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -365,7 +572,7 @@ func (u *URI) Scan(raw interface{}) error {
case string:
*u = URI(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.URI from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.URI from: %#v: %w", v, ErrFormat)
}
return nil
@ -411,7 +618,7 @@ func (u *URI) UnmarshalBSON(data []byte) error {
*u = URI(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as uri")
return fmt.Errorf("couldn't unmarshal bson bytes as uri: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -453,7 +660,7 @@ func (e *Email) Scan(raw interface{}) error {
case string:
*e = Email(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Email from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.Email from: %#v: %w", v, ErrFormat)
}
return nil
@ -499,7 +706,7 @@ func (e *Email) UnmarshalBSON(data []byte) error {
*e = Email(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as email")
return fmt.Errorf("couldn't unmarshal bson bytes as email: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -541,7 +748,7 @@ func (h *Hostname) Scan(raw interface{}) error {
case string:
*h = Hostname(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Hostname from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.Hostname from: %#v: %w", v, ErrFormat)
}
return nil
@ -587,7 +794,7 @@ func (h *Hostname) UnmarshalBSON(data []byte) error {
*h = Hostname(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as hostname")
return fmt.Errorf("couldn't unmarshal bson bytes as hostname: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -629,7 +836,7 @@ func (u *IPv4) Scan(raw interface{}) error {
case string:
*u = IPv4(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.IPv4 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.IPv4 from: %#v: %w", v, ErrFormat)
}
return nil
@ -675,7 +882,7 @@ func (u *IPv4) UnmarshalBSON(data []byte) error {
*u = IPv4(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as ipv4")
return fmt.Errorf("couldn't unmarshal bson bytes as ipv4: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -717,7 +924,7 @@ func (u *IPv6) Scan(raw interface{}) error {
case string:
*u = IPv6(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.IPv6 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.IPv6 from: %#v: %w", v, ErrFormat)
}
return nil
@ -763,7 +970,7 @@ func (u *IPv6) UnmarshalBSON(data []byte) error {
*u = IPv6(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as ipv6")
return fmt.Errorf("couldn't unmarshal bson bytes as ipv6: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -805,7 +1012,7 @@ func (u *CIDR) Scan(raw interface{}) error {
case string:
*u = CIDR(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.CIDR from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.CIDR from: %#v: %w", v, ErrFormat)
}
return nil
@ -851,7 +1058,7 @@ func (u *CIDR) UnmarshalBSON(data []byte) error {
*u = CIDR(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as CIDR")
return fmt.Errorf("couldn't unmarshal bson bytes as CIDR: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -893,7 +1100,7 @@ func (u *MAC) Scan(raw interface{}) error {
case string:
*u = MAC(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.IPv4 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.IPv4 from: %#v: %w", v, ErrFormat)
}
return nil
@ -939,7 +1146,7 @@ func (u *MAC) UnmarshalBSON(data []byte) error {
*u = MAC(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as MAC")
return fmt.Errorf("couldn't unmarshal bson bytes as MAC: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -981,7 +1188,7 @@ func (u *UUID) Scan(raw interface{}) error {
case string:
*u = UUID(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.UUID from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.UUID from: %#v: %w", v, ErrFormat)
}
return nil
@ -1030,7 +1237,7 @@ func (u *UUID) UnmarshalBSON(data []byte) error {
*u = UUID(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as UUID")
return fmt.Errorf("couldn't unmarshal bson bytes as UUID: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1072,7 +1279,7 @@ func (u *UUID3) Scan(raw interface{}) error {
case string:
*u = UUID3(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.UUID3 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.UUID3 from: %#v: %w", v, ErrFormat)
}
return nil
@ -1121,7 +1328,7 @@ func (u *UUID3) UnmarshalBSON(data []byte) error {
*u = UUID3(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as UUID3")
return fmt.Errorf("couldn't unmarshal bson bytes as UUID3: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1163,7 +1370,7 @@ func (u *UUID4) Scan(raw interface{}) error {
case string:
*u = UUID4(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.UUID4 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.UUID4 from: %#v: %w", v, ErrFormat)
}
return nil
@ -1212,7 +1419,7 @@ func (u *UUID4) UnmarshalBSON(data []byte) error {
*u = UUID4(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as UUID4")
return fmt.Errorf("couldn't unmarshal bson bytes as UUID4: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1254,7 +1461,7 @@ func (u *UUID5) Scan(raw interface{}) error {
case string:
*u = UUID5(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.UUID5 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.UUID5 from: %#v: %w", v, ErrFormat)
}
return nil
@ -1303,7 +1510,7 @@ func (u *UUID5) UnmarshalBSON(data []byte) error {
*u = UUID5(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as UUID5")
return fmt.Errorf("couldn't unmarshal bson bytes as UUID5: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1345,7 +1552,7 @@ func (u *ISBN) Scan(raw interface{}) error {
case string:
*u = ISBN(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.ISBN from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.ISBN from: %#v: %w", v, ErrFormat)
}
return nil
@ -1394,7 +1601,7 @@ func (u *ISBN) UnmarshalBSON(data []byte) error {
*u = ISBN(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as ISBN")
return fmt.Errorf("couldn't unmarshal bson bytes as ISBN: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1436,7 +1643,7 @@ func (u *ISBN10) Scan(raw interface{}) error {
case string:
*u = ISBN10(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.ISBN10 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.ISBN10 from: %#v: %w", v, ErrFormat)
}
return nil
@ -1485,7 +1692,7 @@ func (u *ISBN10) UnmarshalBSON(data []byte) error {
*u = ISBN10(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as ISBN10")
return fmt.Errorf("couldn't unmarshal bson bytes as ISBN10: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1527,7 +1734,7 @@ func (u *ISBN13) Scan(raw interface{}) error {
case string:
*u = ISBN13(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.ISBN13 from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.ISBN13 from: %#v: %w", v, ErrFormat)
}
return nil
@ -1576,7 +1783,7 @@ func (u *ISBN13) UnmarshalBSON(data []byte) error {
*u = ISBN13(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as ISBN13")
return fmt.Errorf("couldn't unmarshal bson bytes as ISBN13: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1618,7 +1825,7 @@ func (u *CreditCard) Scan(raw interface{}) error {
case string:
*u = CreditCard(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.CreditCard from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.CreditCard from: %#v: %w", v, ErrFormat)
}
return nil
@ -1667,7 +1874,7 @@ func (u *CreditCard) UnmarshalBSON(data []byte) error {
*u = CreditCard(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as CreditCard")
return fmt.Errorf("couldn't unmarshal bson bytes as CreditCard: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1709,7 +1916,7 @@ func (u *SSN) Scan(raw interface{}) error {
case string:
*u = SSN(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.SSN from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.SSN from: %#v: %w", v, ErrFormat)
}
return nil
@ -1758,7 +1965,7 @@ func (u *SSN) UnmarshalBSON(data []byte) error {
*u = SSN(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as SSN")
return fmt.Errorf("couldn't unmarshal bson bytes as SSN: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1800,7 +2007,7 @@ func (h *HexColor) Scan(raw interface{}) error {
case string:
*h = HexColor(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.HexColor from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.HexColor from: %#v: %w", v, ErrFormat)
}
return nil
@ -1849,7 +2056,7 @@ func (h *HexColor) UnmarshalBSON(data []byte) error {
*h = HexColor(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as HexColor")
return fmt.Errorf("couldn't unmarshal bson bytes as HexColor: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1891,7 +2098,7 @@ func (r *RGBColor) Scan(raw interface{}) error {
case string:
*r = RGBColor(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.RGBColor from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.RGBColor from: %#v: %w", v, ErrFormat)
}
return nil
@ -1940,7 +2147,7 @@ func (r *RGBColor) UnmarshalBSON(data []byte) error {
*r = RGBColor(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as RGBColor")
return fmt.Errorf("couldn't unmarshal bson bytes as RGBColor: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.
@ -1983,7 +2190,7 @@ func (r *Password) Scan(raw interface{}) error {
case string:
*r = Password(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Password from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.Password from: %#v: %w", v, ErrFormat)
}
return nil
@ -2032,7 +2239,7 @@ func (r *Password) UnmarshalBSON(data []byte) error {
*r = Password(ud)
return nil
}
return errors.New("couldn't unmarshal bson bytes as Password")
return fmt.Errorf("couldn't unmarshal bson bytes as Password: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.

View file

@ -17,8 +17,8 @@ package strfmt
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"math"
"regexp"
"strconv"
"strings"
@ -33,6 +33,11 @@ func init() {
Default.Add("duration", &d, IsDuration)
}
const (
hoursInDay = 24
daysInWeek = 7
)
var (
timeUnits = [][]string{
{"ns", "nano"},
@ -52,11 +57,11 @@ var (
"s": time.Second,
"m": time.Minute,
"h": time.Hour,
"d": 24 * time.Hour,
"w": 7 * 24 * time.Hour,
"d": hoursInDay * time.Hour,
"w": hoursInDay * daysInWeek * time.Hour,
}
durationMatcher = regexp.MustCompile(`((\d+)\s*([A-Za-zµ]+))`)
durationMatcher = regexp.MustCompile(`^(((?:-\s?)?\d+)(\.\d+)?\s*([A-Za-zµ]+))`)
)
// IsDuration returns true if the provided string is a valid duration
@ -96,13 +101,35 @@ func ParseDuration(cand string) (time.Duration, error) {
var dur time.Duration
ok := false
const expectGroups = 4
for _, match := range durationMatcher.FindAllStringSubmatch(cand, -1) {
if len(match) < expectGroups {
continue
}
factor, err := strconv.Atoi(match[2]) // converts string to int
// remove possible leading - and spaces
value, negative := strings.CutPrefix(match[2], "-")
// if the duration contains a decimal separator determine a divising factor
const neutral = 1.0
divisor := neutral
decimal, hasDecimal := strings.CutPrefix(match[3], ".")
if hasDecimal {
divisor = math.Pow10(len(decimal))
value += decimal // consider the value as an integer: will change units later on
}
// if the string is a valid duration, parse it
factor, err := strconv.Atoi(strings.TrimSpace(value)) // converts string to int
if err != nil {
return 0, err
}
unit := strings.ToLower(strings.TrimSpace(match[3]))
if negative {
factor = -factor
}
unit := strings.ToLower(strings.TrimSpace(match[4]))
for _, variants := range timeUnits {
last := len(variants) - 1
@ -111,6 +138,9 @@ func ParseDuration(cand string) (time.Duration, error) {
for i, variant := range variants {
if (last == i && strings.HasPrefix(unit, variant)) || strings.EqualFold(variant, unit) {
ok = true
if divisor != neutral {
multiplier = time.Duration(float64(multiplier) / divisor) // convert to duration only after having reduced the scale
}
dur += (time.Duration(factor) * multiplier)
}
}
@ -120,7 +150,7 @@ func ParseDuration(cand string) (time.Duration, error) {
if ok {
return dur, nil
}
return 0, fmt.Errorf("unable to parse %s as duration", cand)
return 0, fmt.Errorf("unable to parse %s as duration: %w", cand, ErrFormat)
}
// Scan reads a Duration value from database driver type.
@ -134,7 +164,7 @@ func (d *Duration) Scan(raw interface{}) error {
case nil:
*d = Duration(0)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Duration from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.Duration from: %#v: %w", v, ErrFormat)
}
return nil
@ -192,7 +222,7 @@ func (d *Duration) UnmarshalBSON(data []byte) error {
return nil
}
return errors.New("couldn't unmarshal bson bytes value as Date")
return fmt.Errorf("couldn't unmarshal bson bytes value as Date: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.

10
vendor/github.com/go-openapi/strfmt/errors.go generated vendored Normal file
View file

@ -0,0 +1,10 @@
package strfmt
type strfmtError string
// ErrFormat is an error raised by the strfmt package
const ErrFormat strfmtError = "format error"
func (e strfmtError) Error() string {
return string(e)
}

View file

@ -16,7 +16,6 @@ package strfmt
import (
"encoding"
stderrors "errors"
"fmt"
"reflect"
"strings"
@ -24,7 +23,7 @@ import (
"time"
"github.com/go-openapi/errors"
"github.com/mitchellh/mapstructure"
"github.com/go-viper/mapstructure/v2"
)
// Default is the default formats registry
@ -50,31 +49,10 @@ type Registry interface {
GetType(string) (reflect.Type, bool)
ContainsName(string) bool
Validates(string, string) bool
Parse(string, string) (interface{}, error)
Parse(string, string) (any, error)
MapStructureHookFunc() mapstructure.DecodeHookFunc
}
type knownFormat struct {
Name string
OrigName string
Type reflect.Type
Validator Validator
}
// NameNormalizer is a function that normalizes a format name.
type NameNormalizer func(string) string
// DefaultNameNormalizer removes all dashes
func DefaultNameNormalizer(name string) string {
return strings.ReplaceAll(name, "-", "")
}
type defaultFormats struct {
sync.Mutex
data []knownFormat
normalizeName NameNormalizer
}
// NewFormats creates a new formats registry seeded with the values from the default
func NewFormats() Registry {
//nolint:forcetypeassert
@ -94,15 +72,37 @@ func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry {
}
}
type knownFormat struct {
Name string
OrigName string
Type reflect.Type
Validator Validator
}
// NameNormalizer is a function that normalizes a format name.
type NameNormalizer func(string) string
// DefaultNameNormalizer removes all dashes
func DefaultNameNormalizer(name string) string {
return strings.ReplaceAll(name, "-", "")
}
type defaultFormats struct {
sync.Mutex
data []knownFormat
normalizeName NameNormalizer
}
// MapStructureHookFunc is a decode hook function for mapstructure
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 any) (any, error) {
if from.Kind() != reflect.String {
return obj, nil
}
data, ok := obj.(string)
if !ok {
return nil, fmt.Errorf("failed to cast %+v to string", obj)
return nil, fmt.Errorf("failed to cast %+v to string: %w", obj, ErrFormat)
}
for _, v := range f.data {
@ -118,7 +118,7 @@ func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc {
case "datetime":
input := data
if len(input) == 0 {
return nil, stderrors.New("empty string is an invalid datetime format")
return nil, fmt.Errorf("empty string is an invalid datetime format: %w", ErrFormat)
}
return ParseDateTime(input)
case "duration":
@ -307,7 +307,7 @@ func (f *defaultFormats) Validates(name, data string) bool {
// Parse a string into the appropriate format representation type.
//
// E.g. parsing a string a "date" will return a Date type.
func (f *defaultFormats) Parse(name, data string) (interface{}, error) {
func (f *defaultFormats) Parse(name, data string) (any, error) {
f.Lock()
defer f.Unlock()
nme := f.normalizeName(name)

View file

@ -18,7 +18,6 @@ import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"
@ -30,7 +29,8 @@ import (
)
var (
// UnixZero sets the zero unix timestamp we want to compare against.
// UnixZero sets the zero unix UTC timestamp we want to compare against.
//
// Unix 0 for an EST timezone is not equivalent to a UTC timezone.
UnixZero = time.Unix(0, 0).UTC()
)
@ -40,13 +40,19 @@ func init() {
Default.Add("datetime", &dt, IsDateTime)
}
// IsDateTime returns true when the string is a valid date-time
// IsDateTime returns true when the string is a valid date-time.
//
// JSON datetime format consist of a date and a time separated by a "T", e.g. 2012-04-23T18:25:43.511Z.
func IsDateTime(str string) bool {
if len(str) < 4 {
const (
minDateTimeLength = 4
minParts = 2
)
if len(str) < minDateTimeLength {
return false
}
s := strings.Split(strings.ToLower(str), "t")
if len(s) < 2 || !IsDate(s[0]) {
if len(s) < minParts || !IsDate(s[0]) {
return false
}
@ -76,7 +82,7 @@ const (
ISO8601TimeWithReducedPrecisionLocaltime = "2006-01-02T15:04"
// ISO8601TimeUniversalSortableDateTimePattern represents a ISO8601 universal sortable date time pattern.
ISO8601TimeUniversalSortableDateTimePattern = "2006-01-02 15:04:05"
// short form of ISO8601TimeUniversalSortableDateTimePattern
// ISO8601TimeUniversalSortableDateTimePatternShortForm is the 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 = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
@ -91,7 +97,7 @@ var (
// MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
MarshalFormat = RFC3339Millis
// NormalizeTimeForMarshal provides a normalization function on time befeore marshalling (e.g. time.UTC).
// NormalizeTimeForMarshal provides a normalization function on time before marshalling (e.g. time.UTC).
// By default, the time value is not changed.
NormalizeTimeForMarshal = func(t time.Time) time.Time { return t }
@ -116,7 +122,8 @@ func ParseDateTime(data string) (DateTime, error) {
return DateTime{}, lastError
}
// DateTime is a time but it serializes to ISO8601 format with millis
// DateTime is a time but it serializes to ISO8601 format with millis.
//
// It knows how to read 3 different variations of a RFC3339 date time.
// Most APIs we encounter want either millisecond or second precision times.
// This just tries to make it worry-free.
@ -124,30 +131,35 @@ func ParseDateTime(data string) (DateTime, error) {
// swagger:strfmt date-time
type DateTime time.Time
// NewDateTime is a representation of zero value for DateTime type
// NewDateTime is a representation of the UNIX epoch (January 1, 1970 00:00:00 UTC) for the [DateTime] type.
//
// Notice that this is not the zero value of the [DateTime] type.
//
// You may use [DateTime.IsUNIXZero] to check against this value.
func NewDateTime() DateTime {
return DateTime(time.Unix(0, 0).UTC())
}
// MakeDateTime is a representation of the zero value of the [DateTime] type (January 1, year 1, 00:00:00 UTC).
//
// You may use [Datetime.IsZero] to check against this value.
func MakeDateTime() DateTime {
return DateTime(time.Time{})
}
// String converts this time to a string
func (t DateTime) String() string {
return NormalizeTimeForMarshal(time.Time(t)).Format(MarshalFormat)
}
// IsZero returns whether the date time is a zero value
func (t *DateTime) IsZero() bool {
if t == nil {
return true
}
return time.Time(*t).IsZero()
func (t DateTime) IsZero() bool {
return time.Time(t).IsZero()
}
// IsUnixZerom returns whether the date time is equivalent to time.Unix(0, 0).UTC().
func (t *DateTime) IsUnixZero() bool {
if t == nil {
return true
}
return time.Time(*t).Equal(UnixZero)
// IsUnixZero returns whether the date time is equivalent to time.Unix(0, 0).UTC().
func (t DateTime) IsUnixZero() bool {
return time.Time(t).Equal(UnixZero)
}
// MarshalText implements the text marshaller interface
@ -178,7 +190,7 @@ func (t *DateTime) Scan(raw interface{}) error {
case nil:
*t = DateTime{}
default:
return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v)
return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v: %w", v, ErrFormat)
}
return nil
@ -232,20 +244,23 @@ func (t *DateTime) UnmarshalBSON(data []byte) error {
return nil
}
const bsonDateLength = 8
// MarshalBSONValue is an interface implemented by types that can marshal themselves
// into a BSON document represented as bytes. The bytes returned must be a valid
// BSON document if the error is nil.
//
// Marshals a DateTime as a bsontype.DateTime, an int64 representing
// milliseconds since epoch.
func (t DateTime) MarshalBSONValue() (bsontype.Type, []byte, error) {
// UnixNano cannot be used directly, the result of calling UnixNano on the zero
// Time is undefined. Thats why we use time.Nanosecond() instead.
// Time is undefined. That's why we use time.Nanosecond() instead.
tNorm := NormalizeTimeForMarshal(time.Time(t))
i64 := tNorm.Unix()*1000 + int64(tNorm.Nanosecond())/1e6
i64 := tNorm.UnixMilli()
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, uint64(i64))
buf := make([]byte, bsonDateLength)
// int64 -> uint64 conversion is safe here
binary.LittleEndian.PutUint64(buf, uint64(i64)) //nolint:gosec
return bson.TypeDateTime, buf, nil
}
@ -260,13 +275,14 @@ func (t *DateTime) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
return nil
}
if len(data) != 8 {
return errors.New("bson date field length not exactly 8 bytes")
if len(data) != bsonDateLength {
return fmt.Errorf("bson date field length not exactly 8 bytes: %w", ErrFormat)
}
i64 := int64(binary.LittleEndian.Uint64(data))
// it's ok to get negative values after conversion
i64 := int64(binary.LittleEndian.Uint64(data)) //nolint:gosec
// TODO: Use bsonprim.DateTime.Time() method
*t = DateTime(time.Unix(i64/1000, i64%1000*1000000))
*t = DateTime(time.UnixMilli(i64))
return nil
}

View file

@ -4,7 +4,6 @@ import (
cryptorand "crypto/rand"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"io"
"sync"
@ -98,7 +97,7 @@ func NewULID() (ULID, error) {
obj := ulidEntropyPool.Get()
entropy, ok := obj.(io.Reader)
if !ok {
return u, fmt.Errorf("failed to cast %+v to io.Reader", obj)
return u, fmt.Errorf("failed to cast %+v to io.Reader: %w", obj, ErrFormat)
}
id, err := ulid.New(ulid.Now(), entropy)
@ -181,12 +180,12 @@ func (u *ULID) UnmarshalBSON(data []byte) error {
if ud, ok := m["data"].(string); ok {
id, err := ulid.ParseStrict(ud)
if err != nil {
return fmt.Errorf("couldn't parse bson bytes as ULID: %w", err)
return fmt.Errorf("couldn't parse bson bytes as ULID: %w: %w", err, ErrFormat)
}
u.ULID = id
return nil
}
return errors.New("couldn't unmarshal bson bytes as ULID")
return fmt.Errorf("couldn't unmarshal bson bytes as ULID: %w", ErrFormat)
}
// DeepCopyInto copies the receiver and writes its value into out.

4
vendor/github.com/go-openapi/swag/.codecov.yml generated vendored Normal file
View file

@ -0,0 +1,4 @@
ignore:
- jsonutils/fixtures_test
- jsonutils/adapters/ifaces/mocks
- jsonutils/adapters/testintegration/benchmarks

View file

@ -17,7 +17,7 @@ linters:
- gomoddirectives
- gosmopolitan
- inamedparam
- intrange # disabled while < go1.22
- intrange
- ireturn
- lll
- musttag
@ -29,6 +29,7 @@ linters:
- recvcheck
- testpackage
- thelper
- tagliatelle
- tparallel
- unparam
- varnamelen

30
vendor/github.com/go-openapi/swag/.mockery.yml generated vendored Normal file
View file

@ -0,0 +1,30 @@
all: false
dir: '{{.InterfaceDir}}'
filename: mocks_test.go
force-file-write: true
formatter: goimports
include-auto-generated: false
log-level: info
structname: '{{.Mock}}{{.InterfaceName}}'
pkgname: '{{.SrcPackageName}}'
recursive: false
require-template-schema-exists: true
template: matryer
template-schema: '{{.Template}}.schema.json'
packages:
github.com/go-openapi/swag/jsonutils/adapters/ifaces:
config:
dir: jsonutils/adapters/ifaces/mocks
filename: mocks.go
pkgname: 'mocks'
force-file-write: true
all: true
github.com/go-openapi/swag/jsonutils/adapters/testintegration:
config:
inpackage: true
dir: jsonutils/adapters/testintegration
force-file-write: true
all: true
interfaces:
EJMarshaler:
EJUnmarshaler:

View file

@ -9,91 +9,103 @@ Package `swag` contains a bunch of helper functions for go-openapi and go-swagge
You may also use it standalone for your projects.
> **NOTE**
> `swag` is one of the foundational building blocks of the go-openapi initiative.
>
> Most repositories in `github.com/go-openapi/...` depend on it in some way.
> So does the CLI tool `github.com/go-swagger/go-swagger`,
> and the code generated by this tool.
> And so does our CLI tool `github.com/go-swagger/go-swagger`,
> as well as the code generated by this tool.
* [Contents](#contents)
* [Dependencies](#dependencies)
* [Release Notes](#release-notes)
* [Note to contributors](#note-to-contributors)
* [TODOs, suggestions and plans](#todos-suggestions-and-plans)
## Contents
`go-openapi/swag` now exposes a collection of relatively independent modules.
`go-openapi/swag` exposes a collection of relatively independent modules.
Here is what is inside:
Moving forward, no additional feature will be added to the `swag` API directly at the root package level,
which remains there for backward-compatibility purposes. All exported top-level features are now deprecated.
* Module `cmdutils`
Child modules will continue to evolve and some new ones may be added in the future.
* [x] utilities to work with CLIs
* Module `conv`
* [x] convert between values and pointers for any types
* [x] convert from string to builtin types (wraps `strconv`)
* [x] require `./typeutils` (test dependency)
* Module `fileutils`
* [x] file upload type
* [x] search in path (deprecated)
* Module `jsonname`
* [x] infer JSON names from go properties
* Module `jsonutils`
* [x] fast json concatenation
* [x] read and write JSON from and to dynamic go data structures
* [x] require `github.com/mailru/easyjson`
* Module `loading`
* [x] load from file or http
* [x] require `./yamlutils`
* Module `mangling`
* [x] name mangling for go
* Module `netutils`
* [x] host, port from address
* Module `stringutils`
* [x] search in slice (with case-insensitive)
* [x] split/join query parameters as arrays
* Module `typeutils`
* [x] check the zero value for any type
* Module `yamlutils`
* [x] converting YAML to JSON
* [x] loading YAML into a dynamic YAML document
* [x] require `./jsonutils`
* [x] require `github.com/mailru/easyjson`
* [x] require `gopkg.in/yaml.v3`
| Module | Content | Main features |
|---------------|---------|---------------|
| `cmdutils` | utilities to work with CLIs ||
| `conv` | type conversion utilities | convert between values and pointers for any types<br />convert from string to builtin types (wraps `strconv`)<br />require `./typeutils` (test dependency)<br /> |
| `fileutils` | file utilities | |
| `jsonname` | JSON utilities | infer JSON names from `go` properties<br /> |
| `jsonutils` | JSON utilities | fast json concatenation<br />read and write JSON from and to dynamic `go` data structures<br />~require `github.com/mailru/easyjson`~<br /> |
| `loading` | file loading | load from file or http<br />require `./yamlutils`<br /> |
| `mangling` | safe name generation | name mangling for `go`<br /> |
| `netutils` | networking utilities | host, port from address<br /> |
| `stringutils` | `string` utilities | search in slice (with case-insensitive)<br />split/join query parameters as arrays<br /> |
| `typeutils` | `go` types utilities | check the zero value for any type<br />safe check for a nil value<br /> |
| `yamlutils` | YAML utilities | converting YAML to JSON<br />loading YAML into a dynamic YAML document<br />maintaining the original order of keys in YAML objects<br />require `./jsonutils`<br />~require `github.com/mailru/easyjson`~<br />require `go.yaml.in/yaml/v3`<br /> |
---
## Dependencies
The root module `github.com/go-openapi/swag` at the repo level maintains a few
dependencies outside of the standard library:
dependencies outside of the standard library.
* YAML utilities depend on `gopkg.in/yaml.v3`
* JSON utilities `github.com/mailru/easyjson`
This is not necessarily the case for all sub-modules.
* YAML utilities depend on `go.yaml.in/yaml/v3`
* JSON utilities depend on their registered adapter module:
* by default, only the standard library is used
* `github.com/mailru/easyjson` is now only a dependency for module
`github.com/go-openapi/swag/jsonutils/adapters/easyjson/json`,
for users willing to import that module.
* integration tests and benchmarks use all the dependencies are published as their own module
* other dependencies are test dependencies drawn from `github.com/stretchr/testify`
## Release notes
### v0.25.0 [draft, unreleased]
### v0.25.1
* v0.25.0 will remove the dependency to `mailru/easyjson` by default.
* users of JSON or YAML utility who want to use `easyjson` as their
prefered JSON marshaler will be able to do so by registering it
at runtime.
* fixes a data race that could occur when using the standard library implementation of a JSON ordered map
### v0.25.0
**New with this release**:
* requires `go1.24`, as iterators are being introduced
* removes the dependency to `mailru/easyjson` by default (#68)
* functionality remains the same, but performance may somewhat degrade for applications
that relied on `easyjson`
* users of the JSON or YAML utilities who want to use `easyjson` as their prefered JSON serializer library
will be able to do so by registering this the corresponding JSON adapter at runtime. See below.
* ordered keys in JSON and YAML objects: this feature used to rely solely on `easyjson`.
With this release, an implementation relying on the standard `encoding/json` is provided.
* an independent [benchmark](./jsonutils/adapters/testintegration/benchmarks/README.md) to compare the different adapters
* improves the "float is integer" check (`conv.IsFloat64AJSONInteger`) (#59)
* removes the _direct_ dependency to `gopkg.in/yaml.v3` (indirect dependency is still incurred through `stretchr/testify`) (#127)
* exposed `conv.IsNil()` (previously kept private): a safe nil check (accounting for the "non-nil interface with nil value" nonsensical go trick)
**What coming next?**
Moving forward, we want to :
* provide an implementation of the JSON adapter based on `encoding/json/v2`, for `go1.25` builds.
* provide similar implementations for `goccy/go-json` and `jsoniterator/go`, and perhaps some other
similar libraries may be interesting too.
**How to explicitly register a dependency at runtime**?
The following would maintain how JSON utilities proposed by `swag` used work, up to `v0.24.1`.
```go
import "github.com/go-openapi/swag/jsonutils/adapters/easyjson/json"
func init() {
json.Register()
}
```
Subsequent calls to `jsonutils.ReadJSON()` or `jsonutils.WriteJSON()` will switch to `easyjson`
whenever the passed data structures implement the `easyjson.Unmarshaler` or `easyjson.Marshaler` respectively,
or fallback to the standard library.
### v0.24.0
@ -121,14 +133,9 @@ With this release, we have largely modernized the API of `swag`:
---
Moving forward, no additional feature will be added to the `swag` API directly.
## Note to contributors
However, child modules will continue to evolve or some new ones may be added in the future.
#### Note to contributors
The mono-repo structure comes with some unavoidable extra pains...
A mono-repo structure comes with some unavoidable extra pains...
* Testing
@ -153,7 +160,14 @@ The mono-repo structure comes with some unavoidable extra pains...
> We'd like to adopt the rule that modules in this repo would only differ by a patch version
> (e.g. `v0.24.5` vs `v0.24.3`), and we'll level all modules whenever a minor version is introduced.
>
> A script in `./hack` is provided to tag all modules in one go at the same level in one go.
> A script in `./hack` is provided to tag all modules with the same version in one go.
* Continuous integration
> At this moment, all tests in all modules are systematically run over the full test matrix (3 platform x 2 go releases).
> This generates quite a lot of jobs.
>
> We ought to reduce the number of jobs required to test a PR focused on only a few modules.
## Todos, suggestions and plans
@ -161,11 +175,18 @@ All kinds of contributions are welcome.
A few ideas:
* [ ] Complete the split of dependencies to isolate easyjson from the rest
* [x] Complete the split of dependencies to isolate easyjson from the rest
* [x] Improve CI to reduce needed tests
* [x] Replace dependency to `gopkg.in/yaml.v3` (`yamlutil`)
* [ ] Improve mangling utilities (improve readability, support for capitalized words,
better word substitution for non-letter symbols...)
* [ ] Move back to this common shared pot a few of the technical features introduced by go-swagger independently
(e.g. mangle go package names, search package with go modules support, ...)
* [ ] Apply a similar mono-repo approach to go-openapi/strfmt which suffer from similar woes: bloated API,
imposed dependency to some database driver.
* [ ] Adapt `go-swagger` (incl. generated code) to the new `swag` API.
* [ ] Factorize some tests, as there is a lot of redundant testing code in `jsonutils`
* [ ] Benchmark & profiling: publish independently the tool built to analyze and chart benchmarks (e.g. similar to `benchvisual`)
* [ ] more thorough testing for nil / null case
* [ ] ci pipeline to manage releases
* [ ] cleaner mockery generation (doesn't work out of the box for all sub-modules)

1
vendor/github.com/go-openapi/swag/TODO.md generated vendored Normal file
View file

@ -0,0 +1 @@
fix data race https://github.com/go-openapi/swag/actions/runs/17989156861/job/51174860188

View file

@ -16,63 +16,43 @@
//
// You may also use it standalone for your projects.
//
// NOTE: all features that were previously exposed as package-level members (constants, variables,
// NOTE: all features that used to be exposed as package-level members (constants, variables,
// functions and types) are now deprecated and are superseded by equivalent features in
// more specialized sub-packages.
// Moving forward, no additional feature will be added to the [swag] API directly at the root package level,
// which remains there for backward-compatibility purposes.
//
// Here is what is inside:
// Child modules will continue to evolve or some new ones may be added in the future.
//
// Module [cmdutils]:
// # Modules
//
// - utilities to work with CLIs
// - [cmdutils] utilities to work with CLIs
//
// Module [conv]:
// - [conv] type conversion utilities
//
// - convert between value and pointers for builtin types
// - convert from string to builtin types (wraps strconv)
// - [fileutils] file utilities
//
// Module [fileutils]:
// - [jsonname] JSON utilities
//
// - file upload type
// - search in path
// - [jsonutils] JSON utilities
//
// Module [jsonname]:
// - [loading] file loading
//
// - json names for go properties
// - [mangling] safe name generation
//
// Module [jsonutils]:
// - [netutils] networking utilities
//
// - fast json concatenation
// - read and write JSON from and to dynamic go data structures
// - [stringutils] `string` utilities
//
// Module [loading]:
// - [typeutils] `go` types utilities
//
// - load from file or http
// - [yamlutils] YAML utilities
//
// Module [mangling]:
//
// - name mangling to generate clean identifiers
//
// Module [netutils]:
//
// - host, port from address
//
// Module [stringutils]:
//
// - find string in list
// - join/split arrays of query parameters
//
// Module [typeutils]:
//
// - check the zero value of any type
//
// Module [yamlutils]:
//
// - converting YAML to JSON
// - loading YAML into a dynamic YAML document
// # Dependencies
//
// This repo has a few dependencies outside of the standard library:
//
// - YAML utilities depend on [gopkg.in/yaml.v3]
// - JSON utilities depend on [github.com/mailru/easyjson]
// - YAML utilities depend on [go.yaml.in/yaml/v3]
package swag
//go:generate mockery

View file

@ -38,11 +38,17 @@ func FindInSearchPath(searchPath, pkg string) string {
}
// FindInGoSearchPath finds a package in the $GOPATH:$GOROOT
//
// Deprecated: this function is no longer relevant with modern go.
// It uses [runtime.GOROOT] under the hood, which is deprecated as of go1.24.
func FindInGoSearchPath(pkg string) string {
return FindInSearchPath(FullGoSearchPath(), pkg)
}
// FullGoSearchPath gets the search paths for finding packages
//
// Deprecated: this function is no longer relevant with modern go.
// It uses [runtime.GOROOT] under the hood, which is deprecated as of go1.24.
func FullGoSearchPath() string {
allPaths := os.Getenv(GOPATHKey)
if allPaths == "" {

20
vendor/github.com/go-openapi/swag/go.work generated vendored Normal file
View file

@ -0,0 +1,20 @@
use (
.
./cmdutils
./conv
./fileutils
./jsonname
./jsonutils
./jsonutils/adapters/easyjson
./jsonutils/adapters/testintegration
./jsonutils/adapters/testintegration/benchmarks
./jsonutils/fixtures_test
./loading
./mangling
./netutils
./stringutils
./typeutils
./yamlutils
)
go 1.24.0

4
vendor/github.com/go-openapi/swag/go.work.sum generated vendored Normal file
View file

@ -0,0 +1,4 @@
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=

108
vendor/github.com/go-openapi/swag/jsonutils/README.md generated vendored Normal file
View file

@ -0,0 +1,108 @@
# jsonutils
`jsonutils` exposes a few tools to work with JSON:
- a fast, simple `Concat` to concatenate (not merge) JSON objects and arrays
- `FromDynamicJSON` to convert a data structure into a "dynamic JSON" data structure
- `ReadJSON` and `WriteJSON` behave like `json.Unmarshal` and `json.Marshal`,
with the ability to use another underlying serialization library through an `Adapter`
configured at runtime
- a `JSONMapSlice` structure that may be used to store JSON objects with the order of keys maintained
## Dynamic JSON
We call "dynamic JSON" the go data structure that results from unmarshaling JSON like this:
```go
var value any
jsonBytes := `{"a": 1, ... }`
_ = json.Unmarshal(jsonBytes, &value)
```
In this configuration, the standard library mappings are as follows:
| JSON | go |
|-----------|------------------|
| `number` | `float64` |
| `string` | `string` |
| `boolean` | `bool` |
| `null` | `nil` |
| `object` | `map[string]any` |
| `array` | `[]any` |
## Map slices
When using `JSONMapSlice`, the ordering of keys is ensured by replacing
mappings to `map[string]any` by a `JSONMapSlice` which is an (ordered)
slice of `JSONMapItem`s.
Notice that a similar feature is available for YAML (see [`yamlutils`](../yamlutils)),
with a `YAMLMapSlice` type based on the `JSONMapSlice`.
`JSONMapSlice` is similar to an ordered map, but the keys are not retrieved
in constant time.
Another difference with the the above standard mappings is that numbers don't always map
to a `float64`: if the value is a JSON integer, it unmarshals to `int64`.
See also [some examples](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils#pkg-examples)
## Adapters
`ReadJSON`, `WriteJSON` and `FromDynamicJSON` (which is a combination of the latter two)
are wrappers on top of `json.Unmarshal` and `json.Marshal`.
By default, the adapter merely wraps the standard library.
The adapter may be used to register other JSON serialization libraries,
possibly several ones at the same time.
If the value passed is identified as an "ordered map" (i.e. implements `ifaces.Ordered`
or `ifaces.SetOrdered`, the adapter favors the "ordered" JSON behavior and tries to
find a registered implementation that support ordered keys in objects.
Our standard library implementation supports this.
As of `v0.25.0`, we support through such an adapter the popular `mailru/easyjson`
library, which kicks in when the passed values support the `easyjson.Unmarshaler`
or `easyjson.Marshaler` interfaces.
In the future, we plan to add more similar libraries that compete on the go JSON
serializers scene.
## Registering an adapter
In package `github.com/go-openapi/swag/easyjson/adapters`, several adapters are available.
Each adapter is an independent go module. Hence you'll pick its dependencies only if you import it.
At this moment we provide:
* `stdlib`: JSON adapter based on the standard library
* `easyjson`: JSON adapter based on the `github.com/mailru/easyyjson`
The adapters provide the basic `Marshal` and `Unmarshal` capabilities, plus an implementation
of the `MapSlice` pattern.
You may also build your own adapter based on your specific use-case. An adapter is not required to implement
all capabilities.
Every adapter comes with a `Register` function, possibly with some options, to register the adapter
to a global registry.
For example, to enable `easyjson` to be used in `ReadJSON` and `WriteJSON`, you would write something like:
```go
import (
"github.com/go-openapi/swag/jsonutils/adapters"
easyjson "github.com/go-openapi/swag/jsonutils/adapters/easyjson/json"
)
func init() {
easyjson.Register(adapters.Registry)
}
```
You may register several adapters. In this case, capability matching is evaluated from the last registered
adapters (LIFO).
## [Benchmarks](./adapters/testintegration/benchmarks/README.md)

View file

@ -0,0 +1,19 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package adapters exposes a registry of adapters to multiple
// JSON serialization libraries.
//
// All interfaces are defined in package [ifaces.Adapter].
package adapters

View file

@ -0,0 +1,2 @@
// Package ifaces exposes all interfaces to work with adapters.
package ifaces

View file

@ -0,0 +1,81 @@
package ifaces
import (
_ "encoding/json" // for documentation purpose
"iter"
)
// Ordered knows how to iterate over the (key,value) pairs of a JSON object.
type Ordered interface {
OrderedItems() iter.Seq2[string, any]
}
// SetOrdered knows how to append or update the keys of a JSON object,
// given an iterator over (key,value) pairs.
//
// If the provided iterator is nil then the receiver should be set to nil.
type SetOrdered interface {
SetOrderedItems(iter.Seq2[string, any])
}
// OrderedMap represent a JSON object (i.e. like a map[string,any]),
// and knows how to serialize and deserialize JSON with the order of keys maintained.
type OrderedMap interface {
Ordered
SetOrdered
OrderedMarshalJSON() ([]byte, error)
OrderedUnmarshalJSON([]byte) error
}
// MarshalAdapter behaves likes the standard library [json.Marshal].
type MarshalAdapter interface {
Poolable
Marshal(any) ([]byte, error)
}
// OrderedMarshalAdapter behaves likes the standard library [json.Marshal], preserving the order of keys in objects.
type OrderedMarshalAdapter interface {
Poolable
OrderedMarshal(Ordered) ([]byte, error)
}
// UnmarshalAdapter behaves likes the standard library [json.Unmarshal].
type UnmarshalAdapter interface {
Poolable
Unmarshal([]byte, any) error
}
// OrderedUnmarshalAdapter behaves likes the standard library [json.Unmarshal], preserving the order of keys in objects.
type OrderedUnmarshalAdapter interface {
Poolable
OrderedUnmarshal([]byte, SetOrdered) error
}
// Adapter exposes an interface like the standard [json] library.
type Adapter interface {
MarshalAdapter
UnmarshalAdapter
OrderedAdapter
}
// OrderedAdapter exposes interfaces to process JSON and keep the order of object keys.
type OrderedAdapter interface {
OrderedMarshalAdapter
OrderedUnmarshalAdapter
NewOrderedMap(capacity int) OrderedMap
}
type Poolable interface {
// Self-redeem: for [Adapter] s that are allocated from a pool.
// The [Adapter] must not be used after calling [Redeem].
Redeem()
// Reset the state of the [Adapter], if any.
Reset()
}

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