fix(deps): update module github.com/prometheus/alertmanager to v0.29.0 (main) (#19797)

Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
Co-authored-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
This commit is contained in:
renovate-sh-app[bot]
2025-11-10 17:08:11 -05:00
committed by GitHub
co-authored by renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
parent abaeff7fad
commit 5ec7ddca47
245 changed files with 25771 additions and 7617 deletions
+31 -22
View File
@@ -85,7 +85,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_model v0.6.2
github.com/prometheus/common v0.66.1
github.com/prometheus/common v0.67.1
github.com/prometheus/prometheus v0.305.1-0.20250806170547-208187eaa19b
github.com/redis/go-redis/v9 v9.10.0
github.com/segmentio/fasthash v1.0.3
@@ -142,7 +142,7 @@ require (
github.com/oklog/ulid/v2 v2.1.1
github.com/parquet-go/parquet-go v0.25.1
github.com/pressly/goose/v3 v3.26.0
github.com/prometheus/alertmanager v0.28.1
github.com/prometheus/alertmanager v0.29.0
github.com/prometheus/common/sigv4 v0.1.0
github.com/prometheus/otlptranslator v0.0.2
github.com/prometheus/sigv4 v0.2.1
@@ -209,6 +209,17 @@ require (
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.2 // indirect
github.com/go-ole/go-ole v1.3.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-viper/mapstructure/v2 v2.4.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.5 // indirect
@@ -268,7 +279,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zeebo/errs v1.4.0 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/collector/component v1.35.0 // indirect
go.opentelemetry.io/collector/confmap v1.35.0 // indirect
go.opentelemetry.io/collector/confmap/xconfmap v0.129.0 // indirect
@@ -300,10 +311,10 @@ require (
go.opentelemetry.io/otel/sdk/log v0.12.2 // indirect
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect
golang.org/x/tools/godoc v0.1.0-deprecated // indirect
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
modernc.org/libc v1.66.3 // indirect
@@ -352,7 +363,7 @@ require (
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/coreos/go-systemd/v22 v22.6.0 // indirect
github.com/dennwc/varint v1.0.0 // indirect
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -372,15 +383,15 @@ require (
github.com/felixge/httpsnoop v1.0.4 // 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/errors v0.22.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // 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/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-openapi/analysis v0.24.0 // indirect
github.com/go-openapi/errors v0.22.3 // 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/strfmt v0.24.0 // indirect
github.com/go-openapi/swag v0.25.1 // indirect
github.com/go-openapi/validate v0.25.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.26.0 // indirect
@@ -414,14 +425,12 @@ require (
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.68 // indirect
@@ -437,7 +446,7 @@ require (
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/exporter-toolkit v0.14.0 // indirect
github.com/prometheus/exporter-toolkit v0.14.1 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
github.com/rs/xid v1.6.0 // indirect
@@ -455,7 +464,7 @@ require (
go.etcd.io/etcd/api/v3 v3.5.4 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect
go.etcd.io/etcd/client/v3 v3.5.4 // indirect
go.mongodb.org/mongo-driver v1.17.2 // indirect
go.mongodb.org/mongo-driver v1.17.4 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/collector/semconv v0.128.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0
@@ -465,9 +474,9 @@ require (
go.opentelemetry.io/otel/trace v1.38.0
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/mod v0.28.0 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/term v0.36.0 // indirect
golang.org/x/tools v0.37.0 // indirect
golang.org/x/tools v0.38.0 // indirect
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda
+64 -41
View File
@@ -323,8 +323,8 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=
github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
@@ -455,24 +455,48 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
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.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
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/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.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
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/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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -738,7 +762,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joncrlsn/dque v0.0.0-20211108142734-c2ef48c5192a h1:sfe532Ipn7GX0V6mHdynBk393rDmqgI0QmjLK7ct7TU=
github.com/joncrlsn/dque v0.0.0-20211108142734-c2ef48c5192a/go.mod h1:dNKs71rs2VJGBAmttu7fouEsRQlRjxy0p1Sx+T5wbpY=
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/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
@@ -808,8 +831,6 @@ github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a h1:3Bm7EwfUQUvhNeKIkUct/gl9eod1TcXuj8stxvi/GoI=
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
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/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
@@ -969,8 +990,8 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM=
github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY=
github.com/prometheus/alertmanager v0.28.1 h1:BK5pCoAtaKg01BYRUJhEDV1tqJMEtYBGzPw8QdvnnvA=
github.com/prometheus/alertmanager v0.28.1/go.mod h1:0StpPUDDHi1VXeM7p2yYfeZgLVi/PPlt39vo9LQUHxM=
github.com/prometheus/alertmanager v0.29.0 h1:/ET4NmAGx2Dv9kStrXIBqBgHyiSgIk4OetY+hoZRfgc=
github.com/prometheus/alertmanager v0.29.0/go.mod h1:SjI2vhrfdWg10UaRUxTz27rgdJVG3HXrhI5WFjCdBgs=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
@@ -992,12 +1013,12 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
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/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI=
github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q=
github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4=
github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg=
github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA=
github.com/prometheus/exporter-toolkit v0.14.1 h1:uKPE4ewweVRWFainwvAcHs3uw15pjw2dk3I7b+aNo9o=
github.com/prometheus/exporter-toolkit v0.14.1/go.mod h1:di7yaAJiaMkcjcz48f/u4yRPwtyuxTU5Jr4EnM2mhtQ=
github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ=
github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -1170,8 +1191,8 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.4 h1:lrneYvz923dvC14R54XcA7FXoZ3mlGZAgmwhfm7H
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v3 v3.5.4 h1:p83BUL3tAYS0OT/r0qglgc3M1JjhM0diV8DSWAhVXv4=
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
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.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -1179,8 +1200,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
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/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/collector/component v1.35.0 h1:JpvBukEcEUvJ/TInF1KYpXtWEP+C7iYkxCHKjI0o7BQ=
go.opentelemetry.io/collector/component v1.35.0/go.mod h1:hU/ieWPxWbMAacODCSqem5ZaN6QH9W5GWiZ3MtXVuwc=
go.opentelemetry.io/collector/component/componentstatus v0.129.0 h1:ejpBAt7hXAAZiQKcSxLvcy8sj8SjY4HOLdoXIlW6ybw=
@@ -1300,8 +1321,10 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
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=
go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s=
go4.org/netipx v0.0.0-20230125063823-8449b0a6169f/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1358,8 +1381,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1492,8 +1515,8 @@ golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8=
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -1569,8 +1592,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+6 -4
View File
@@ -13,7 +13,6 @@
// limitations under the License.
//go:build !windows
// +build !windows
// Package activation implements primitives for systemd socket activation.
package activation
@@ -38,9 +37,12 @@ const (
// fd usage and to avoid leaking environment flags to child processes.
func Files(unsetEnv bool) []*os.File {
if unsetEnv {
defer os.Unsetenv("LISTEN_PID")
defer os.Unsetenv("LISTEN_FDS")
defer os.Unsetenv("LISTEN_FDNAMES")
defer func() {
// Unsetenv implementation for unix never returns an error.
_ = os.Unsetenv("LISTEN_PID")
_ = os.Unsetenv("LISTEN_FDS")
_ = os.Unsetenv("LISTEN_FDNAMES")
}()
}
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
+1 -1
View File
@@ -41,6 +41,6 @@ const (
)
// Print prints a message to the local systemd journal using Send().
func Print(priority Priority, format string, a ...interface{}) error {
func Print(priority Priority, format string, a ...any) error {
return Send(fmt.Sprintf(format, a...), priority, nil)
}
+3 -5
View File
@@ -13,7 +13,6 @@
// limitations under the License.
//go:build !windows
// +build !windows
// Package journal provides write bindings to the local systemd journal.
// It is implemented in pure Go and connects to the journal directly over its
@@ -31,7 +30,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"os"
"strconv"
@@ -194,7 +192,7 @@ func appendVariable(w io.Writer, name, value string) {
* - the data, followed by a newline
*/
fmt.Fprintln(w, name)
binary.Write(w, binary.LittleEndian, uint64(len(value)))
_ = binary.Write(w, binary.LittleEndian, uint64(len(value)))
fmt.Fprintln(w, value)
} else {
/* just write the variable and value all on one line */
@@ -214,7 +212,7 @@ func validVarName(name string) error {
}
for _, c := range name {
if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') {
if ('A' > c || c > 'Z') && ('0' > c || c > '9') && c != '_' {
return errors.New("Variable name contains invalid characters")
}
}
@@ -239,7 +237,7 @@ func isSocketSpaceError(err error) bool {
// tempFd creates a temporary, unlinked file under `/dev/shm`.
func tempFd() (*os.File, error) {
file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX")
file, err := os.CreateTemp("/dev/shm/", "journal.XXXXX")
if err != nil {
return nil, err
}
+70 -56
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
+583 -579
View File
File diff suppressed because it is too large Load Diff
+53
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,
)
}
+1 -1
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)"
+12 -13
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 {
+12 -6
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 {
@@ -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
@@ -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,
)
}
+36 -41
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
@@ -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
}
+18 -17
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
}
+6 -6
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 {
+1 -3
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{
+70 -57
View File
@@ -1,62 +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:
- errname # this repo doesn't follow the convention advised by this linter
- 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
+4 -4
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,13 +179,13 @@ 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)))
}
}
}
func asHTTPCode(input int) int {
if input >= 600 {
if input >= maximumValidHTTPCode {
return DefaultHTTPCode
}
return input
+1 -1
View File
@@ -21,7 +21,7 @@ import (
)
// Validation represents a failure of a precondition
type Validation struct {
type Validation struct { //nolint: errname
code int32
Name string
In string
+3 -3
View File
@@ -22,7 +22,7 @@ import (
// APIVerificationFailed is an error that contains all the missing info for a mismatched section
// between the api registrations and the api spec
type APIVerificationFailed struct {
type APIVerificationFailed struct { //nolint: errname
Section string `json:"section,omitempty"`
MissingSpecification []string `json:"missingSpecification,omitempty"`
MissingRegistration []string `json:"missingRegistration,omitempty"`
@@ -35,7 +35,7 @@ func (v *APIVerificationFailed) Error() string {
hasSpecMissing := len(v.MissingSpecification) > 0
if hasRegMissing {
buf.WriteString(fmt.Sprintf("missing [%s] %s registrations", strings.Join(v.MissingRegistration, ", "), v.Section))
fmt.Fprintf(buf, "missing [%s] %s registrations", strings.Join(v.MissingRegistration, ", "), v.Section)
}
if hasRegMissing && hasSpecMissing {
@@ -43,7 +43,7 @@ func (v *APIVerificationFailed) Error() string {
}
if hasSpecMissing {
buf.WriteString(fmt.Sprintf("missing from spec file [%s] %s", strings.Join(v.MissingSpecification, ", "), v.Section))
fmt.Fprintf(buf, "missing from spec file [%s] %s", strings.Join(v.MissingSpecification, ", "), v.Section)
}
return buf.String()
+19 -18
View File
@@ -17,6 +17,7 @@ package errors
import (
"encoding/json"
"fmt"
"net/http"
)
// ParseError represents a parsing error
@@ -29,6 +30,24 @@ type ParseError struct {
message string
}
// NewParseError creates a new parse error
func NewParseError(name, in, value string, reason error) *ParseError {
var msg string
if in == "" {
msg = fmt.Sprintf(parseErrorTemplContentNoIn, name, value, reason)
} else {
msg = fmt.Sprintf(parseErrorTemplContent, name, in, value, reason)
}
return &ParseError{
code: http.StatusBadRequest,
Name: name,
In: in,
Value: value,
Reason: reason,
message: msg,
}
}
func (e *ParseError) Error() string {
return e.message
}
@@ -58,21 +77,3 @@ const (
parseErrorTemplContent = `parsing %s %s from %q failed, because %s`
parseErrorTemplContentNoIn = `parsing %s from %q failed, because %s`
)
// NewParseError creates a new parse error
func NewParseError(name, in, value string, reason error) *ParseError {
var msg string
if in == "" {
msg = fmt.Sprintf(parseErrorTemplContentNoIn, name, value, reason)
} else {
msg = fmt.Sprintf(parseErrorTemplContent, name, in, value, reason)
}
return &ParseError{
code: 400,
Name: name,
In: in,
Value: value,
Reason: reason,
message: msg,
}
}
+57 -53
View File
@@ -17,6 +17,7 @@ package errors
import (
"encoding/json"
"fmt"
"net/http"
"strings"
)
@@ -32,12 +33,12 @@ const (
patternFail = "%s in %s should match '%s'"
enumFail = "%s in %s should be one of %v"
multipleOfFail = "%s in %s should be a multiple of %v"
maxIncFail = "%s in %s should be less than or equal to %v"
maxExcFail = "%s in %s should be less than %v"
maximumIncFail = "%s in %s should be less than or equal to %v"
maximumExcFail = "%s in %s should be less than %v"
minIncFail = "%s in %s should be greater than or equal to %v"
minExcFail = "%s in %s should be greater than %v"
uniqueFail = "%s in %s shouldn't contain duplicates"
maxItemsFail = "%s in %s should have at most %d items"
maximumItemsFail = "%s in %s should have at most %d items"
minItemsFail = "%s in %s should have at least %d items"
typeFailNoIn = "%s must be of type %s"
typeFailWithDataNoIn = "%s must be of type %s: %q"
@@ -49,12 +50,12 @@ const (
patternFailNoIn = "%s should match '%s'"
enumFailNoIn = "%s should be one of %v"
multipleOfFailNoIn = "%s should be a multiple of %v"
maxIncFailNoIn = "%s should be less than or equal to %v"
maxExcFailNoIn = "%s should be less than %v"
maximumIncFailNoIn = "%s should be less than or equal to %v"
maximumExcFailNoIn = "%s should be less than %v"
minIncFailNoIn = "%s should be greater than or equal to %v"
minExcFailNoIn = "%s should be greater than %v"
uniqueFailNoIn = "%s shouldn't contain duplicates"
maxItemsFailNoIn = "%s should have at most %d items"
maximumItemsFailNoIn = "%s should have at most %d items"
minItemsFailNoIn = "%s should have at least %d items"
noAdditionalItems = "%s in %s can't have additional items"
noAdditionalItemsNoIn = "%s can't have additional items"
@@ -69,14 +70,17 @@ const (
multipleOfMustBePositive = "factor MultipleOf declared for %s must be positive: %v"
)
const maximumValidHTTPCode = 600
// All code responses can be used to differentiate errors for different handling
// by the consuming program
const (
// CompositeErrorCode remains 422 for backwards-compatibility
// and to separate it from validation errors with cause
CompositeErrorCode = 422
CompositeErrorCode = http.StatusUnprocessableEntity
// InvalidTypeCode is used for any subclass of invalid types
InvalidTypeCode = 600 + iota
InvalidTypeCode = maximumValidHTTPCode + iota
RequiredFailCode
TooLongFailCode
TooShortFailCode
@@ -298,10 +302,10 @@ func DuplicateItems(name, in string) *Validation {
}
// TooManyItems error for when an array contains too many items
func TooManyItems(name, in string, max int64, value interface{}) *Validation {
msg := fmt.Sprintf(maxItemsFail, name, in, max)
func TooManyItems(name, in string, maximum int64, value interface{}) *Validation {
msg := fmt.Sprintf(maximumItemsFail, name, in, maximum)
if in == "" {
msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
msg = fmt.Sprintf(maximumItemsFailNoIn, name, maximum)
}
return &Validation{
@@ -314,10 +318,10 @@ func TooManyItems(name, in string, max int64, value interface{}) *Validation {
}
// TooFewItems error for when an array contains too few items
func TooFewItems(name, in string, min int64, value interface{}) *Validation {
msg := fmt.Sprintf(minItemsFail, name, in, min)
func TooFewItems(name, in string, minimum int64, value interface{}) *Validation {
msg := fmt.Sprintf(minItemsFail, name, in, minimum)
if in == "" {
msg = fmt.Sprintf(minItemsFailNoIn, name, min)
msg = fmt.Sprintf(minItemsFailNoIn, name, minimum)
}
return &Validation{
code: MinItemsFailCode,
@@ -328,21 +332,21 @@ func TooFewItems(name, in string, min int64, value interface{}) *Validation {
}
}
// ExceedsMaximumInt error for when maximum validation fails
func ExceedsMaximumInt(name, in string, max int64, exclusive bool, value interface{}) *Validation {
// ExceedsMaximumInt error for when maximumimum validation fails
func ExceedsMaximumInt(name, in string, maximum int64, exclusive bool, value interface{}) *Validation {
var message string
if in == "" {
m := maxIncFailNoIn
m := maximumIncFailNoIn
if exclusive {
m = maxExcFailNoIn
m = maximumExcFailNoIn
}
message = fmt.Sprintf(m, name, max)
message = fmt.Sprintf(m, name, maximum)
} else {
m := maxIncFail
m := maximumIncFail
if exclusive {
m = maxExcFail
m = maximumExcFail
}
message = fmt.Sprintf(m, name, in, max)
message = fmt.Sprintf(m, name, in, maximum)
}
return &Validation{
code: MaxFailCode,
@@ -353,21 +357,21 @@ func ExceedsMaximumInt(name, in string, max int64, exclusive bool, value interfa
}
}
// ExceedsMaximumUint error for when maximum validation fails
func ExceedsMaximumUint(name, in string, max uint64, exclusive bool, value interface{}) *Validation {
// ExceedsMaximumUint error for when maximumimum validation fails
func ExceedsMaximumUint(name, in string, maximum uint64, exclusive bool, value interface{}) *Validation {
var message string
if in == "" {
m := maxIncFailNoIn
m := maximumIncFailNoIn
if exclusive {
m = maxExcFailNoIn
m = maximumExcFailNoIn
}
message = fmt.Sprintf(m, name, max)
message = fmt.Sprintf(m, name, maximum)
} else {
m := maxIncFail
m := maximumIncFail
if exclusive {
m = maxExcFail
m = maximumExcFail
}
message = fmt.Sprintf(m, name, in, max)
message = fmt.Sprintf(m, name, in, maximum)
}
return &Validation{
code: MaxFailCode,
@@ -378,21 +382,21 @@ func ExceedsMaximumUint(name, in string, max uint64, exclusive bool, value inter
}
}
// ExceedsMaximum error for when maximum validation fails
func ExceedsMaximum(name, in string, max float64, exclusive bool, value interface{}) *Validation {
// ExceedsMaximum error for when maximumimum validation fails
func ExceedsMaximum(name, in string, maximum float64, exclusive bool, value interface{}) *Validation {
var message string
if in == "" {
m := maxIncFailNoIn
m := maximumIncFailNoIn
if exclusive {
m = maxExcFailNoIn
m = maximumExcFailNoIn
}
message = fmt.Sprintf(m, name, max)
message = fmt.Sprintf(m, name, maximum)
} else {
m := maxIncFail
m := maximumIncFail
if exclusive {
m = maxExcFail
m = maximumExcFail
}
message = fmt.Sprintf(m, name, in, max)
message = fmt.Sprintf(m, name, in, maximum)
}
return &Validation{
code: MaxFailCode,
@@ -404,20 +408,20 @@ func ExceedsMaximum(name, in string, max float64, exclusive bool, value interfac
}
// ExceedsMinimumInt error for when minimum validation fails
func ExceedsMinimumInt(name, in string, min int64, exclusive bool, value interface{}) *Validation {
func ExceedsMinimumInt(name, in string, minimum int64, exclusive bool, value interface{}) *Validation {
var message string
if in == "" {
m := minIncFailNoIn
if exclusive {
m = minExcFailNoIn
}
message = fmt.Sprintf(m, name, min)
message = fmt.Sprintf(m, name, minimum)
} else {
m := minIncFail
if exclusive {
m = minExcFail
}
message = fmt.Sprintf(m, name, in, min)
message = fmt.Sprintf(m, name, in, minimum)
}
return &Validation{
code: MinFailCode,
@@ -429,20 +433,20 @@ func ExceedsMinimumInt(name, in string, min int64, exclusive bool, value interfa
}
// ExceedsMinimumUint error for when minimum validation fails
func ExceedsMinimumUint(name, in string, min uint64, exclusive bool, value interface{}) *Validation {
func ExceedsMinimumUint(name, in string, minimum uint64, exclusive bool, value interface{}) *Validation {
var message string
if in == "" {
m := minIncFailNoIn
if exclusive {
m = minExcFailNoIn
}
message = fmt.Sprintf(m, name, min)
message = fmt.Sprintf(m, name, minimum)
} else {
m := minIncFail
if exclusive {
m = minExcFail
}
message = fmt.Sprintf(m, name, in, min)
message = fmt.Sprintf(m, name, in, minimum)
}
return &Validation{
code: MinFailCode,
@@ -454,20 +458,20 @@ func ExceedsMinimumUint(name, in string, min uint64, exclusive bool, value inter
}
// ExceedsMinimum error for when minimum validation fails
func ExceedsMinimum(name, in string, min float64, exclusive bool, value interface{}) *Validation {
func ExceedsMinimum(name, in string, minimum float64, exclusive bool, value interface{}) *Validation {
var message string
if in == "" {
m := minIncFailNoIn
if exclusive {
m = minExcFailNoIn
}
message = fmt.Sprintf(m, name, min)
message = fmt.Sprintf(m, name, minimum)
} else {
m := minIncFail
if exclusive {
m = minExcFail
}
message = fmt.Sprintf(m, name, in, min)
message = fmt.Sprintf(m, name, in, minimum)
}
return &Validation{
code: MinFailCode,
@@ -549,12 +553,12 @@ func ReadOnly(name, in string, value interface{}) *Validation {
}
// TooLong error for when a string is too long
func TooLong(name, in string, max int64, value interface{}) *Validation {
func TooLong(name, in string, maximum int64, value interface{}) *Validation {
var msg string
if in == "" {
msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
msg = fmt.Sprintf(tooLongMessageNoIn, name, maximum)
} else {
msg = fmt.Sprintf(tooLongMessage, name, in, max)
msg = fmt.Sprintf(tooLongMessage, name, in, maximum)
}
return &Validation{
code: TooLongFailCode,
@@ -566,12 +570,12 @@ func TooLong(name, in string, max int64, value interface{}) *Validation {
}
// TooShort error for when a string is too short
func TooShort(name, in string, min int64, value interface{}) *Validation {
func TooShort(name, in string, minimum int64, value interface{}) *Validation {
var msg string
if in == "" {
msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
msg = fmt.Sprintf(tooShortMessageNoIn, name, minimum)
} else {
msg = fmt.Sprintf(tooShortMessage, name, in, min)
msg = fmt.Sprintf(tooShortMessage, name, in, minimum)
}
return &Validation{
+70 -56
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
+8 -1
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 "-".
+18
View File
@@ -0,0 +1,18 @@
package jsonpointer
type pointerError string
func (e pointerError) Error() string {
return string(e)
}
const (
// ErrPointer is an error raised by the jsonpointer package
ErrPointer pointerError = "JSON pointer error"
// ErrInvalidStart states that a JSON pointer must start with a separator ("/")
ErrInvalidStart pointerError = `JSON pointer must be empty or start with a "` + pointerSeparator
// ErrUnsupportedValueType indicates that a value of the wrong type is being set
ErrUnsupportedValueType pointerError = "only structs, pointers, maps and slices are supported for setting values"
)
+307 -303
View File
@@ -33,19 +33,18 @@ import (
"strconv"
"strings"
"github.com/go-openapi/swag"
"github.com/go-openapi/swag/jsonname"
)
const (
emptyPointer = ``
pointerSeparator = `/`
invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator
notFound = `Can't find the pointer in the document`
)
var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
var 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
@@ -59,303 +58,30 @@ 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
}
// "Constructor", parses the given string JSON pointer
func (p *Pointer) parse(jsonPointerString string) error {
// New creates a new json pointer for the given string
func New(jsonPointerString string) (Pointer, error) {
var p Pointer
err := p.parse(jsonPointerString)
var err error
if jsonPointerString != emptyPointer {
if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
err = errors.New(invalidStart)
} else {
referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...)
}
}
return err
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, swag.DefaultJSONNameProvider)
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, swag.DefaultJSONNameProvider)
return document, p.set(document, value, jsonname.DefaultJSONNameProvider)
}
// 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)
}
// 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)
}
func isNil(input any) bool {
if input == nil {
return true
}
kind := reflect.TypeOf(input).Kind()
switch kind { //nolint:exhaustive
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
return reflect.ValueOf(input).IsNil()
default:
return false
}
}
func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if isNil(node) {
return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken)
}
switch typed := node.(type) {
case JSONPointable:
r, err := typed.JSONLookup(decodedToken)
if err != nil {
return nil, kind, err
}
return r, kind, nil
case *any: // case of a pointer to interface, that is not resolved by reflect.Indirect
return getSingleImpl(*typed, decodedToken, nameProvider)
}
switch kind { //nolint:exhaustive
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return nil, kind, fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
return fld.Interface(), kind, nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if mv.IsValid() {
return mv.Interface(), kind, nil
}
return nil, kind, fmt.Errorf("object has no key %q", decodedToken)
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return nil, kind, err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex)
}
elem := rValue.Index(tokenIndex)
return elem.Interface(), kind, nil
default:
return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken)
}
}
func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameProvider) error {
rValue := reflect.Indirect(reflect.ValueOf(node))
if ns, ok := node.(JSONSetable); ok { // pointer impl
return ns.JSONSet(decodedToken, data)
}
if rValue.Type().Implements(jsonSetableType) {
return node.(JSONSetable).JSONSet(decodedToken, data)
}
switch rValue.Kind() { //nolint:exhaustive
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
if fld.IsValid() {
fld.Set(reflect.ValueOf(data))
}
return nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
rValue.SetMapIndex(kv, reflect.ValueOf(data))
return nil
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'", sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if !elem.CanSet() {
return fmt.Errorf("can't set slice index %s to %v", decodedToken, data)
}
elem.Set(reflect.ValueOf(data))
return nil
default:
return fmt.Errorf("invalid token reference %q", decodedToken)
}
}
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.New("only structs, pointers, maps and slices are supported for setting values")
}
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)
}
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", decodedToken)
}
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", decodedToken)
}
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'", sLength, tokenIndex)
}
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", decodedToken)
}
}
return nil
}
// DecodedTokens returns the decoded tokens
// 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 {
@@ -377,9 +103,7 @@ func (p *Pointer) String() string {
return emptyPointer
}
pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
return pointerString
return pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
}
func (p *Pointer) Offset(document string) (int64, error) {
@@ -404,15 +128,294 @@ func (p *Pointer) Offset(document string) (int64, error) {
return 0, err
}
default:
return 0, fmt.Errorf("invalid token %#v", tk)
return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
}
default:
return 0, fmt.Errorf("invalid token %#v", tk)
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 {
if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
err = errors.Join(ErrInvalidStart, ErrPointer)
} else {
referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...)
}
}
return err
}
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
}
func (p *Pointer) set(node, data any, nameProvider *jsonname.NameProvider) error {
knd := reflect.ValueOf(node).Kind()
if knd != reflect.Pointer && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
return errors.Join(
ErrUnsupportedValueType,
ErrPointer,
)
}
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 {
if input == nil {
return true
}
kind := reflect.TypeOf(input).Kind()
switch kind { //nolint:exhaustive
case reflect.Pointer, reflect.Map, reflect.Slice, reflect.Chan:
return reflect.ValueOf(input).IsNil()
default:
return false
}
}
// 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) {
return nil, kind, fmt.Errorf("nil value has no field %q: %w", decodedToken, ErrPointer)
}
switch typed := node.(type) {
case JSONPointable:
r, err := typed.JSONLookup(decodedToken)
if err != nil {
return nil, kind, err
}
return r, kind, nil
case *any: // case of a pointer to interface, that is not resolved by reflect.Indirect
return getSingleImpl(*typed, decodedToken, nameProvider)
}
switch kind { //nolint:exhaustive
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return nil, kind, fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
}
fld := rValue.FieldByName(nm)
return fld.Interface(), kind, nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if mv.IsValid() {
return mv.Interface(), kind, nil
}
return nil, kind, fmt.Errorf("object has no key %q: %w", decodedToken, ErrPointer)
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return nil, kind, err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength-1, tokenIndex, ErrPointer)
}
elem := rValue.Index(tokenIndex)
return elem.Interface(), kind, nil
default:
return nil, kind, fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
}
}
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()
if isNil(node) {
return fmt.Errorf("cannot set field %q on nil value: %w", decodedToken, ErrPointer)
}
if ns, ok := node.(JSONSetable); ok { // pointer impl
return ns.JSONSet(decodedToken, data)
}
if rValue.Type().Implements(jsonSetableType) {
return node.(JSONSetable).JSONSet(decodedToken, data)
}
switch rValue.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.IsValid() {
fld.Set(reflect.ValueOf(data))
}
return nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
rValue.SetMapIndex(kv, reflect.ValueOf(data))
return nil
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.CanSet() {
return fmt.Errorf("can't set slice index %s to %v: %w", decodedToken, data, ErrPointer)
}
elem.Set(reflect.ValueOf(data))
return nil
default:
return fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
}
}
func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
for dec.More() {
offset := dec.InputOffset()
@@ -437,16 +440,16 @@ func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
return offset, nil
}
default:
return 0, fmt.Errorf("invalid token %#v", tk)
return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
}
}
return 0, fmt.Errorf("token reference %q not found", decodedToken)
return 0, fmt.Errorf("token reference %q not found: %w", decodedToken, ErrPointer)
}
func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
idx, err := strconv.Atoi(decodedToken)
if err != nil {
return 0, fmt.Errorf("token reference %q is not a number: %v", decodedToken, err)
return 0, fmt.Errorf("token reference %q is not a number: %v: %w", decodedToken, err, ErrPointer)
}
var i int
for i = 0; i < idx && dec.More(); i++ {
@@ -470,7 +473,7 @@ func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
}
if !dec.More() {
return 0, fmt.Errorf("token reference %q not found", decodedToken)
return 0, fmt.Errorf("token reference %q not found: %w", decodedToken, ErrPointer)
}
return dec.InputOffset(), nil
}
@@ -516,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)
}
+70 -56
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
+38 -39
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
}
+70 -56
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
+23 -1
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).
+1 -1
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
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"
)
+31 -12
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
}
+15 -2
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
}
}
+43 -31
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
}
+70 -56
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
+2 -2
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
}
+3
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")
)
+6 -4
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) {
+10 -10
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
+2 -2
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
+10 -10
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
+2 -2
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
}
+20 -17
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
+10 -10
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
}
+2 -2
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
}
+7 -6
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
}
+2 -1
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.
+23 -21
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
}
+2 -2
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
+17 -17
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
+3 -3
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
}
+38 -36
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
}
+26 -24
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 {
+2 -2
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
+3 -3
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)
}
}
+7 -7
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
+8 -4
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)
}()
+70 -56
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
+3 -3
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)
+2 -3
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.
+292 -85
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.
+39 -9
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
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)
}
+28 -28
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)
+46 -30
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
}
+3 -4
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
View File
@@ -0,0 +1,4 @@
ignore:
- jsonutils/fixtures_test
- jsonutils/adapters/ifaces/mocks
- jsonutils/adapters/testintegration/benchmarks
+72 -55
View File
@@ -1,60 +1,77 @@
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0
gocyclo:
min-complexity: 45
maligned:
suggest-new: true
dupl:
threshold: 200
goconst:
min-len: 3
min-occurrences: 3
version: "2"
linters:
enable-all: true
default: all
disable:
- maligned
- 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
- gomoddirectives
- gosmopolitan
- inamedparam
- intrange
- ireturn
- lll
- musttag
- nestif
- nlreturn
- nonamedreturns
- noinlineerr
- paralleltest
- recvcheck
- testpackage
- thelper
- tagliatelle
- 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
+30
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:
+180 -11
View File
@@ -1,23 +1,192 @@
# Swag [![Build Status](https://github.com/go-openapi/swag/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/swag/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
[![license](https://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/swag.svg)](https://pkg.go.dev/github.com/go-openapi/swag)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/swag)](https://goreportcard.com/report/github.com/go-openapi/swag)
Contains a bunch of helper functions for go-openapi and go-swagger projects.
Package `swag` contains a bunch of helper functions for go-openapi and go-swagger projects.
You may also use it standalone for your projects.
* convert between value and pointers for builtin types
* convert from string to builtin types (wraps strconv)
* fast json concatenation
* search in path
* load from file or http
* name mangling
> **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.
> 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` exposes a collection of relatively independent modules.
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.
Child modules will continue to evolve and some new ones may be added in the future.
| 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.
* 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.1
* 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.
This repo has only few dependencies outside of the standard library:
**How to explicitly register a dependency at runtime**?
* YAML utilities depend on `gopkg.in/yaml.v3`
* `github.com/mailru/easyjson v0.7.7`
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
With this release, we have largely modernized the API of `swag`:
* The traditional `swag` API is still supported: code that imports `swag` will still
compile and work the same.
* A deprecation notice is published to encourage consumers of this library to adopt
the newer API
* **Deprecation notice**
* configuration through global variables is now deprecated, in favor of options passed as parameters
* all helper functions are moved to more specialized packages, which are exposed as
go modules. Importing such a module would reduce the footprint of dependencies.
* _all_ functions, variables, constants exposed by the deprecated API have now moved, so
that consumers of the new API no longer need to import github.com/go-openapi/swag, but
should import the desired sub-module(s).
**New with this release**:
* [x] type converters and pointer to value helpers now support generic types
* [x] name mangling now support pluralized initialisms (issue #46)
Strings like "contact IDs" are now recognized as such a plural form and mangled as a linter would expect.
* [x] performance: small improvements to reduce the overhead of convert/format wrappers (see issues #110, or PR #108)
* [x] performance: name mangling utilities run ~ 10% faster (PR #115)
---
## Note to contributors
A mono-repo structure comes with some unavoidable extra pains...
* Testing
> The usual `go test ./...` command, run from the root of this repo won't work any longer to test all submodules.
>
> Each module constitutes an independant unit of test. So you have to run `go test` inside each module.
> Or you may take a look at how this is achieved by CI
> [here] https://github.com/go-openapi/swag/blob/master/.github/workflows/go-test.yml).
>
> There are also some alternative tricks using `go work`, for local development, if you feel comfortable with
> go workspaces. Perhaps some day, we'll have a `go work test` to run all tests without any hack.
* Releasing
> Each module follows its own independant module versioning.
>
> So you have tags like `mangling/v0.24.0`, `fileutils/v0.24.0` etc that are used by `go mod` and `go get`
> to refer to the tagged version of each module specifically.
>
> This means we may release patches etc to each module independently.
>
> 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 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
All kinds of contributions are welcome.
A few ideas:
* [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
View File
@@ -0,0 +1 @@
fix data race https://github.com/go-openapi/swag/actions/runs/17989156861/job/51174860188
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+24
View File
@@ -0,0 +1,24 @@
// 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 cmdutils
// CommandLineOptionsGroup represents a group of user-defined command line options.
//
// This is for instance used to configure command line arguments in API servers generated by go-swagger.
type CommandLineOptionsGroup struct {
ShortDescription string
LongDescription string
Options interface{}
}
+16
View File
@@ -0,0 +1,16 @@
// 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 cmdutils brings helpers for CLIs produced by go-openapi
package cmdutils
+22
View File
@@ -0,0 +1,22 @@
// 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 swag
import "github.com/go-openapi/swag/cmdutils"
// CommandLineOptionsGroup represents a group of user-defined command line options.
//
// Deprecated: use [cmdutils.CommandLineOptionsGroup] instead.
type CommandLineOptionsGroup = cmdutils.CommandLineOptionsGroup
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+172
View File
@@ -0,0 +1,172 @@
// 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 conv
import (
"math"
"strconv"
"strings"
)
// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
const (
maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
epsilon float64 = 1e-9
)
// IsFloat64AJSONInteger allows for integers [-2^53, 2^53-1] inclusive.
func IsFloat64AJSONInteger(f float64) bool {
if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat {
return false
}
rounded := math.Round(f)
if f == rounded {
return true
}
if rounded == 0 { // f = 0.0 exited above
return false
}
diff := math.Abs(f - rounded)
if diff == 0 {
return true
}
// relative error Abs{f - Round(f)) / Round(f)} < ε ; Round(f)
return diff < epsilon*math.Abs(rounded)
}
// ConvertFloat turns a string into a float numerical value.
func ConvertFloat[T Float](str string) (T, error) {
var v T
f, err := strconv.ParseFloat(str, bitsize(v))
if err != nil {
return 0, err
}
return T(f), nil
}
// ConvertInteger turns a string into a signed integer.
func ConvertInteger[T Signed](str string) (T, error) {
var v T
f, err := strconv.ParseInt(str, 10, bitsize(v))
if err != nil {
return 0, err
}
return T(f), nil
}
// ConvertUinteger turns a string into an unsigned integer.
func ConvertUinteger[T Unsigned](str string) (T, error) {
var v T
f, err := strconv.ParseUint(str, 10, bitsize(v))
if err != nil {
return 0, err
}
return T(f), nil
}
// ConvertBool turns a string into a boolean.
//
// It supports a few more "true" strings than [strconv.ParseBool]:
//
// - it is not case sensitive ("trUe" or "FalsE" work)
// - "ok", "yes", "y", "on", "selected", "checked", "enabled" are all true
// - everything that is not true is false: there is never an actual error returned
func ConvertBool(str string) (bool, error) {
switch strings.ToLower(str) {
case "true",
"1",
"yes",
"ok",
"y",
"on",
"selected",
"checked",
"t",
"enabled":
return true, nil
default:
return false, nil
}
}
// ConvertFloat32 turns a string into a float32.
func ConvertFloat32(str string) (float32, error) { return ConvertFloat[float32](str) }
// ConvertFloat64 turns a string into a float64
func ConvertFloat64(str string) (float64, error) { return ConvertFloat[float64](str) }
// ConvertInt8 turns a string into an int8
func ConvertInt8(str string) (int8, error) { return ConvertInteger[int8](str) }
// ConvertInt16 turns a string into an int16
func ConvertInt16(str string) (int16, error) {
i, err := strconv.ParseInt(str, 10, 16)
if err != nil {
return 0, err
}
return int16(i), nil
}
// ConvertInt32 turns a string into an int32
func ConvertInt32(str string) (int32, error) {
i, err := strconv.ParseInt(str, 10, 32)
if err != nil {
return 0, err
}
return int32(i), nil
}
// ConvertInt64 turns a string into an int64
func ConvertInt64(str string) (int64, error) {
return strconv.ParseInt(str, 10, 64)
}
// ConvertUint8 turns a string into an uint8
func ConvertUint8(str string) (uint8, error) {
i, err := strconv.ParseUint(str, 10, 8)
if err != nil {
return 0, err
}
return uint8(i), nil
}
// ConvertUint16 turns a string into an uint16
func ConvertUint16(str string) (uint16, error) {
i, err := strconv.ParseUint(str, 10, 16)
if err != nil {
return 0, err
}
return uint16(i), nil
}
// ConvertUint32 turns a string into an uint32
func ConvertUint32(str string) (uint32, error) {
i, err := strconv.ParseUint(str, 10, 32)
if err != nil {
return 0, err
}
return uint32(i), nil
}
// ConvertUint64 turns a string into an uint64
func ConvertUint64(str string) (uint64, error) {
return strconv.ParseUint(str, 10, 64)
}
+79
View File
@@ -0,0 +1,79 @@
// 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 conv
// The original version of this file, eons ago, was taken from the aws go sdk
// Pointer returns a pointer to the value passed in.
func Pointer[T any](v T) *T {
return &v
}
// Value returns a shallow copy of the value of the pointer passed in.
//
// If the pointer is nil, the returned value is the zero value.
func Value[T any](v *T) T {
if v != nil {
return *v
}
var zero T
return zero
}
// PointerSlice converts a slice of values into a slice of pointers.
func PointerSlice[T any](src []T) []*T {
dst := make([]*T, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// ValueSlice converts a slice of pointers into a slice of values.
//
// nil elements are zero values.
func ValueSlice[T any](src []*T) []T {
dst := make([]T, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// PointerMap converts a map of values into a map of pointers.
func PointerMap[K comparable, T any](src map[K]T) map[K]*T {
dst := make(map[K]*T)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// ValueMap converts a map of pointers into a map of values.
//
// nil elements are skipped.
func ValueMap[K comparable, T any](src map[K]*T) map[K]T {
dst := make(map[K]T)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
+26
View File
@@ -0,0 +1,26 @@
// 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 conv exposes utilities to convert types.
//
// The Convert and Format families of functions are essentially a shorthand to [strconv] functions,
// using the decimal representation of numbers.
//
// Features:
//
// - from string representation to value ("Convert*") and reciprocally ("Format*")
// - from pointer to value ([Value]) and reciprocally ([Pointer])
// - from slice of values to slice of pointers ([PointerSlice]) and reciprocally ([ValueSlice])
// - from map of values to map of pointers ([PointerMap]) and reciprocally ([ValueMap])
package conv
+39
View File
@@ -0,0 +1,39 @@
// 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 conv
import (
"strconv"
)
// FormatInteger turns an integer type into a string.
func FormatInteger[T Signed](value T) string {
return strconv.FormatInt(int64(value), 10)
}
// FormatUinteger turns an unsigned integer type into a string.
func FormatUinteger[T Unsigned](value T) string {
return strconv.FormatUint(uint64(value), 10)
}
// FormatFloat turns a floating point numerical value into a string.
func FormatFloat[T Float](value T) string {
return strconv.FormatFloat(float64(value), 'f', -1, bitsize(value))
}
// FormatBool turns a boolean into a string.
func FormatBool(value bool) string {
return strconv.FormatBool(value)
}
+17
View File
@@ -0,0 +1,17 @@
package conv
import "unsafe"
// bitsize returns the size in bits of a type.
//
// NOTE: [unsafe.SizeOf] simply returns the size in bytes of the value.
// For primitive types T, the generic stencil is precompiled and this value
// is resolved at compile time, resulting in an immediate call to [strconv.ParseFloat].
//
// We may leave up to the go compiler to simplify this function into a
// constant value, which happens in practice at least for primitive types
// (e.g. numerical types).
func bitsize[T Numerical](value T) int {
const bitsPerByte = 8
return int(unsafe.Sizeof(value)) * bitsPerByte
}
+40
View File
@@ -0,0 +1,40 @@
// 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 conv
type (
// these type constraints are redefined after golang.org/x/exp/constraints,
// because importing that package causes an undesired go upgrade.
// Signed integer types, cf. [golang.org/x/exp/constraints.Signed]
Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
// Unsigned integer types, cf. [golang.org/x/exp/constraints.Unsigned]
Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}
// Float numerical types, cf. [golang.org/x/exp/constraints.Float]
Float interface {
~float32 | ~float64
}
// Numerical types
Numerical interface {
Signed | Unsigned | Float
}
)
+497
View File
@@ -0,0 +1,497 @@
// 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 swag
import (
"time"
"github.com/go-openapi/swag/conv"
)
// IsFloat64AJSONInteger allows for integers [-2^53, 2^53-1] inclusive.
//
// Deprecated: use [conv.IsFloat64AJSONInteger] instead.
func IsFloat64AJSONInteger(f float64) bool { return conv.IsFloat64AJSONInteger(f) }
// ConvertBool turns a string into a boolean.
//
// Deprecated: use [conv.ConvertBool] instead.
func ConvertBool(str string) (bool, error) { return conv.ConvertBool(str) }
// ConvertFloat32 turns a string into a float32.
//
// Deprecated: use [conv.ConvertFloat32] instead. Alternatively, you may use the generic version [conv.ConvertFloat].
func ConvertFloat32(str string) (float32, error) { return conv.ConvertFloat[float32](str) }
// ConvertFloat64 turns a string into a float64.
//
// Deprecated: use [conv.ConvertFloat64] instead. Alternatively, you may use the generic version [conv.ConvertFloat].
func ConvertFloat64(str string) (float64, error) { return conv.ConvertFloat[float64](str) }
// ConvertInt8 turns a string into an int8.
//
// Deprecated: use [conv.ConvertInt8] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
func ConvertInt8(str string) (int8, error) { return conv.ConvertInteger[int8](str) }
// ConvertInt16 turns a string into an int16.
//
// Deprecated: use [conv.ConvertInt16] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
func ConvertInt16(str string) (int16, error) { return conv.ConvertInteger[int16](str) }
// ConvertInt32 turns a string into an int32.
//
// Deprecated: use [conv.ConvertInt32] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
func ConvertInt32(str string) (int32, error) { return conv.ConvertInteger[int32](str) }
// ConvertInt64 turns a string into an int64.
//
// Deprecated: use [conv.ConvertInt64] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
func ConvertInt64(str string) (int64, error) { return conv.ConvertInteger[int64](str) }
// ConvertUint8 turns a string into an uint8.
//
// Deprecated: use [conv.ConvertUint8] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
func ConvertUint8(str string) (uint8, error) { return conv.ConvertUinteger[uint8](str) }
// ConvertUint16 turns a string into an uint16.
//
// Deprecated: use [conv.ConvertUint16] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
func ConvertUint16(str string) (uint16, error) { return conv.ConvertUinteger[uint16](str) }
// ConvertUint32 turns a string into an uint32.
//
// Deprecated: use [conv.ConvertUint32] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
func ConvertUint32(str string) (uint32, error) { return conv.ConvertUinteger[uint32](str) }
// ConvertUint64 turns a string into an uint64.
//
// Deprecated: use [conv.ConvertUint64] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
func ConvertUint64(str string) (uint64, error) { return conv.ConvertUinteger[uint64](str) }
// FormatBool turns a boolean into a string.
//
// Deprecated: use [conv.FormatBool] instead.
func FormatBool(value bool) string { return conv.FormatBool(value) }
// FormatFloat32 turns a float32 into a string.
//
// Deprecated: use [conv.FormatFloat] instead.
func FormatFloat32(value float32) string { return conv.FormatFloat(value) }
// FormatFloat64 turns a float64 into a string.
//
// Deprecated: use [conv.FormatFloat] instead.
func FormatFloat64(value float64) string { return conv.FormatFloat(value) }
// FormatInt8 turns an int8 into a string.
//
// Deprecated: use [conv.FormatInteger] instead.
func FormatInt8(value int8) string { return conv.FormatInteger(value) }
// FormatInt16 turns an int16 into a string.
//
// Deprecated: use [conv.FormatInteger] instead.
func FormatInt16(value int16) string { return conv.FormatInteger(value) }
// FormatInt32 turns an int32 into a string
//
// Deprecated: use [conv.FormatInteger] instead.
func FormatInt32(value int32) string { return conv.FormatInteger(value) }
// FormatInt64 turns an int64 into a string.
//
// Deprecated: use [conv.FormatInteger] instead.
func FormatInt64(value int64) string { return conv.FormatInteger(value) }
// FormatUint8 turns an uint8 into a string.
//
// Deprecated: use [conv.FormatUinteger] instead.
func FormatUint8(value uint8) string { return conv.FormatUinteger(value) }
// FormatUint16 turns an uint16 into a string.
//
// Deprecated: use [conv.FormatUinteger] instead.
func FormatUint16(value uint16) string { return conv.FormatUinteger(value) }
// FormatUint32 turns an uint32 into a string.
//
// Deprecated: use [conv.FormatUinteger] instead.
func FormatUint32(value uint32) string { return conv.FormatUinteger(value) }
// FormatUint64 turns an uint64 into a string.
//
// Deprecated: use [conv.FormatUinteger] instead.
func FormatUint64(value uint64) string { return conv.FormatUinteger(value) }
// String turn a pointer to of the string value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func String(v string) *string { return conv.Pointer(v) }
// StringValue turn the value of the string pointer passed in or
// "" if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func StringValue(v *string) string { return conv.Value(v) }
// StringSlice converts a slice of string values into a slice of string pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func StringSlice(src []string) []*string { return conv.PointerSlice(src) }
// StringValueSlice converts a slice of string pointers into a slice of string values.
//
// Deprecated: use [conv.ValueSlice] instead.
func StringValueSlice(src []*string) []string { return conv.ValueSlice(src) }
// StringMap converts a string map of string values into a string map of string pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func StringMap(src map[string]string) map[string]*string { return conv.PointerMap(src) }
// StringValueMap converts a string map of string pointers into a string map of string values.
//
// Deprecated: use [conv.ValueMap] instead.
func StringValueMap(src map[string]*string) map[string]string { return conv.ValueMap(src) }
// Bool turn a pointer to of the bool value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Bool(v bool) *bool { return conv.Pointer(v) }
// BoolValue turn the value of the bool pointer passed in or false if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func BoolValue(v *bool) bool { return conv.Value(v) }
// BoolSlice converts a slice of bool values into a slice of bool pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func BoolSlice(src []bool) []*bool { return conv.PointerSlice(src) }
// BoolValueSlice converts a slice of bool pointers into a slice of bool values.
//
// Deprecated: use [conv.ValueSlice] instead.
func BoolValueSlice(src []*bool) []bool { return conv.ValueSlice(src) }
// BoolMap converts a string map of bool values into a string map of bool pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func BoolMap(src map[string]bool) map[string]*bool { return conv.PointerMap(src) }
// BoolValueMap converts a string map of bool pointers into a string map of bool values.
//
// Deprecated: use [conv.ValueMap] instead.
func BoolValueMap(src map[string]*bool) map[string]bool { return conv.ValueMap(src) }
// Int turn a pointer to of the int value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Int(v int) *int { return conv.Pointer(v) }
// IntValue turn the value of the int pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func IntValue(v *int) int { return conv.Value(v) }
// IntSlice converts a slice of int values into a slice of int pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func IntSlice(src []int) []*int { return conv.PointerSlice(src) }
// IntValueSlice converts a slice of int pointers into a slice of int values.
//
// Deprecated: use [conv.ValueSlice] instead.
func IntValueSlice(src []*int) []int { return conv.ValueSlice(src) }
// IntMap converts a string map of int values into a string map of int pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func IntMap(src map[string]int) map[string]*int { return conv.PointerMap(src) }
// IntValueMap converts a string map of int pointers into a string map of int values.
//
// Deprecated: use [conv.ValueMap] instead.
func IntValueMap(src map[string]*int) map[string]int { return conv.ValueMap(src) }
// Int32 turn a pointer to of the int32 value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Int32(v int32) *int32 { return conv.Pointer(v) }
// Int32Value turn the value of the int32 pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func Int32Value(v *int32) int32 { return conv.Value(v) }
// Int32Slice converts a slice of int32 values into a slice of int32 pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func Int32Slice(src []int32) []*int32 { return conv.PointerSlice(src) }
// Int32ValueSlice converts a slice of int32 pointers into a slice of int32 values.
//
// Deprecated: use [conv.ValueSlice] instead.
func Int32ValueSlice(src []*int32) []int32 { return conv.ValueSlice(src) }
// Int32Map converts a string map of int32 values into a string map of int32 pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func Int32Map(src map[string]int32) map[string]*int32 { return conv.PointerMap(src) }
// Int32ValueMap converts a string map of int32 pointers into a string map of int32 values.
//
// Deprecated: use [conv.ValueMap] instead.
func Int32ValueMap(src map[string]*int32) map[string]int32 { return conv.ValueMap(src) }
// Int64 turn a pointer to of the int64 value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Int64(v int64) *int64 { return conv.Pointer(v) }
// Int64Value turn the value of the int64 pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func Int64Value(v *int64) int64 { return conv.Value(v) }
// Int64Slice converts a slice of int64 values into a slice of int64 pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func Int64Slice(src []int64) []*int64 { return conv.PointerSlice(src) }
// Int64ValueSlice converts a slice of int64 pointers into a slice of int64 values.
//
// Deprecated: use [conv.ValueSlice] instead.
func Int64ValueSlice(src []*int64) []int64 { return conv.ValueSlice(src) }
// Int64Map converts a string map of int64 values into a string map of int64 pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func Int64Map(src map[string]int64) map[string]*int64 { return conv.PointerMap(src) }
// Int64ValueMap converts a string map of int64 pointers into a string map of int64 values.
//
// Deprecated: use [conv.ValueMap] instead.
func Int64ValueMap(src map[string]*int64) map[string]int64 { return conv.ValueMap(src) }
// Uint16 turn a pointer to of the uint16 value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Uint16(v uint16) *uint16 { return conv.Pointer(v) }
// Uint16Value turn the value of the uint16 pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func Uint16Value(v *uint16) uint16 { return conv.Value(v) }
// Uint16Slice converts a slice of uint16 values into a slice of uint16 pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func Uint16Slice(src []uint16) []*uint16 { return conv.PointerSlice(src) }
// Uint16ValueSlice converts a slice of uint16 pointers into a slice of uint16 values.
//
// Deprecated: use [conv.ValueSlice] instead.
func Uint16ValueSlice(src []*uint16) []uint16 { return conv.ValueSlice(src) }
// Uint16Map converts a string map of uint16 values into a string map of uint16 pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func Uint16Map(src map[string]uint16) map[string]*uint16 { return conv.PointerMap(src) }
// Uint16ValueMap converts a string map of uint16 pointers into a string map of uint16 values.
//
// Deprecated: use [conv.ValueMap] instead.
func Uint16ValueMap(src map[string]*uint16) map[string]uint16 { return conv.ValueMap(src) }
// Uint turn a pointer to of the uint value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Uint(v uint) *uint { return conv.Pointer(v) }
// UintValue turn the value of the uint pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func UintValue(v *uint) uint { return conv.Value(v) }
// UintSlice converts a slice of uint values into a slice of uint pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func UintSlice(src []uint) []*uint { return conv.PointerSlice(src) }
// UintValueSlice converts a slice of uint pointers into a slice of uint values.
//
// Deprecated: use [conv.ValueSlice] instead.
func UintValueSlice(src []*uint) []uint { return conv.ValueSlice(src) }
// UintMap converts a string map of uint values into a string map of uint pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func UintMap(src map[string]uint) map[string]*uint { return conv.PointerMap(src) }
// UintValueMap converts a string map of uint pointers into a string map of uint values.
//
// Deprecated: use [conv.ValueMap] instead.
func UintValueMap(src map[string]*uint) map[string]uint { return conv.ValueMap(src) }
// Uint32 turn a pointer to of the uint32 value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Uint32(v uint32) *uint32 { return conv.Pointer(v) }
// Uint32Value turn the value of the uint32 pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func Uint32Value(v *uint32) uint32 { return conv.Value(v) }
// Uint32Slice converts a slice of uint32 values into a slice of uint32 pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func Uint32Slice(src []uint32) []*uint32 { return conv.PointerSlice(src) }
// Uint32ValueSlice converts a slice of uint32 pointers into a slice of uint32 values.
//
// Deprecated: use [conv.ValueSlice] instead.
func Uint32ValueSlice(src []*uint32) []uint32 { return conv.ValueSlice(src) }
// Uint32Map converts a string map of uint32 values into a string map of uint32 pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func Uint32Map(src map[string]uint32) map[string]*uint32 { return conv.PointerMap(src) }
// Uint32ValueMap converts a string map of uint32 pointers into a string map of uint32 values.
//
// Deprecated: use [conv.ValueMap] instead.
func Uint32ValueMap(src map[string]*uint32) map[string]uint32 { return conv.ValueMap(src) }
// Uint64 turn a pointer to of the uint64 value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Uint64(v uint64) *uint64 { return conv.Pointer(v) }
// Uint64Value turn the value of the uint64 pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func Uint64Value(v *uint64) uint64 { return conv.Value(v) }
// Uint64Slice converts a slice of uint64 values into a slice of uint64 pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func Uint64Slice(src []uint64) []*uint64 { return conv.PointerSlice(src) }
// Uint64ValueSlice converts a slice of uint64 pointers into a slice of uint64 values.
//
// Deprecated: use [conv.ValueSlice] instead.
func Uint64ValueSlice(src []*uint64) []uint64 { return conv.ValueSlice(src) }
// Uint64Map converts a string map of uint64 values into a string map of uint64 pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func Uint64Map(src map[string]uint64) map[string]*uint64 { return conv.PointerMap(src) }
// Uint64ValueMap converts a string map of uint64 pointers into a string map of uint64 values.
//
// Deprecated: use [conv.ValueMap] instead.
func Uint64ValueMap(src map[string]*uint64) map[string]uint64 { return conv.ValueMap(src) }
// Float32 turn a pointer to of the float32 value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Float32(v float32) *float32 { return conv.Pointer(v) }
// Float32Value turn the value of the float32 pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func Float32Value(v *float32) float32 { return conv.Value(v) }
// Float32Slice converts a slice of float32 values into a slice of float32 pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func Float32Slice(src []float32) []*float32 { return conv.PointerSlice(src) }
// Float32ValueSlice converts a slice of float32 pointers into a slice of float32 values.
//
// Deprecated: use [conv.ValueSlice] instead.
func Float32ValueSlice(src []*float32) []float32 { return conv.ValueSlice(src) }
// Float32Map converts a string map of float32 values into a string map of float32 pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func Float32Map(src map[string]float32) map[string]*float32 { return conv.PointerMap(src) }
// Float32ValueMap converts a string map of float32 pointers into a string map of float32 values.
//
// Deprecated: use [conv.ValueMap] instead.
func Float32ValueMap(src map[string]*float32) map[string]float32 { return conv.ValueMap(src) }
// Float64 turn a pointer to of the float64 value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Float64(v float64) *float64 { return conv.Pointer(v) }
// Float64Value turn the value of the float64 pointer passed in or 0 if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func Float64Value(v *float64) float64 { return conv.Value(v) }
// Float64Slice converts a slice of float64 values into a slice of float64 pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func Float64Slice(src []float64) []*float64 { return conv.PointerSlice(src) }
// Float64ValueSlice converts a slice of float64 pointers into a slice of float64 values.
//
// Deprecated: use [conv.ValueSlice] instead.
func Float64ValueSlice(src []*float64) []float64 { return conv.ValueSlice(src) }
// Float64Map converts a string map of float64 values into a string map of float64 pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func Float64Map(src map[string]float64) map[string]*float64 { return conv.PointerMap(src) }
// Float64ValueMap converts a string map of float64 pointers into a string map of float64 values.
//
// Deprecated: use [conv.ValueMap] instead.
func Float64ValueMap(src map[string]*float64) map[string]float64 { return conv.ValueMap(src) }
// Time turn a pointer to of the time.Time value passed in.
//
// Deprecated: use [conv.Pointer] instead.
func Time(v time.Time) *time.Time { return conv.Pointer(v) }
// TimeValue turn the value of the time.Time pointer passed in or time.Time{} if the pointer is nil.
//
// Deprecated: use [conv.Value] instead.
func TimeValue(v *time.Time) time.Time { return conv.Value(v) }
// TimeSlice converts a slice of time.Time values into a slice of time.Time pointers.
//
// Deprecated: use [conv.PointerSlice] instead.
func TimeSlice(src []time.Time) []*time.Time { return conv.PointerSlice(src) }
// TimeValueSlice converts a slice of time.Time pointers into a slice of time.Time values
//
// Deprecated: use [conv.ValueSlice] instead.
func TimeValueSlice(src []*time.Time) []time.Time { return conv.ValueSlice(src) }
// TimeMap converts a string map of time.Time values into a string map of time.Time pointers.
//
// Deprecated: use [conv.PointerMap] instead.
func TimeMap(src map[string]time.Time) map[string]*time.Time { return conv.PointerMap(src) }
// TimeValueMap converts a string map of time.Time pointers into a string map of time.Time values.
//
// Deprecated: use [conv.ValueMap] instead.
func TimeValueMap(src map[string]*time.Time) map[string]time.Time { return conv.ValueMap(src) }
-208
View File
@@ -1,208 +0,0 @@
// 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 swag
import (
"math"
"strconv"
"strings"
)
// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
const (
maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
epsilon float64 = 1e-9
)
// IsFloat64AJSONInteger allow for integers [-2^53, 2^53-1] inclusive
func IsFloat64AJSONInteger(f float64) bool {
if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat {
return false
}
fa := math.Abs(f)
g := float64(uint64(f))
ga := math.Abs(g)
diff := math.Abs(f - g)
// more info: https://floating-point-gui.de/errors/comparison/#look-out-for-edge-cases
switch {
case f == g: // best case
return true
case f == float64(int64(f)) || f == float64(uint64(f)): // optimistic case
return true
case f == 0 || g == 0 || diff < math.SmallestNonzeroFloat64: // very close to 0 values
return diff < (epsilon * math.SmallestNonzeroFloat64)
}
// check the relative error
return diff/math.Min(fa+ga, math.MaxFloat64) < epsilon
}
var evaluatesAsTrue map[string]struct{}
func init() {
evaluatesAsTrue = map[string]struct{}{
"true": {},
"1": {},
"yes": {},
"ok": {},
"y": {},
"on": {},
"selected": {},
"checked": {},
"t": {},
"enabled": {},
}
}
// ConvertBool turn a string into a boolean
func ConvertBool(str string) (bool, error) {
_, ok := evaluatesAsTrue[strings.ToLower(str)]
return ok, nil
}
// ConvertFloat32 turn a string into a float32
func ConvertFloat32(str string) (float32, error) {
f, err := strconv.ParseFloat(str, 32)
if err != nil {
return 0, err
}
return float32(f), nil
}
// ConvertFloat64 turn a string into a float64
func ConvertFloat64(str string) (float64, error) {
return strconv.ParseFloat(str, 64)
}
// ConvertInt8 turn a string into an int8
func ConvertInt8(str string) (int8, error) {
i, err := strconv.ParseInt(str, 10, 8)
if err != nil {
return 0, err
}
return int8(i), nil
}
// ConvertInt16 turn a string into an int16
func ConvertInt16(str string) (int16, error) {
i, err := strconv.ParseInt(str, 10, 16)
if err != nil {
return 0, err
}
return int16(i), nil
}
// ConvertInt32 turn a string into an int32
func ConvertInt32(str string) (int32, error) {
i, err := strconv.ParseInt(str, 10, 32)
if err != nil {
return 0, err
}
return int32(i), nil
}
// ConvertInt64 turn a string into an int64
func ConvertInt64(str string) (int64, error) {
return strconv.ParseInt(str, 10, 64)
}
// ConvertUint8 turn a string into an uint8
func ConvertUint8(str string) (uint8, error) {
i, err := strconv.ParseUint(str, 10, 8)
if err != nil {
return 0, err
}
return uint8(i), nil
}
// ConvertUint16 turn a string into an uint16
func ConvertUint16(str string) (uint16, error) {
i, err := strconv.ParseUint(str, 10, 16)
if err != nil {
return 0, err
}
return uint16(i), nil
}
// ConvertUint32 turn a string into an uint32
func ConvertUint32(str string) (uint32, error) {
i, err := strconv.ParseUint(str, 10, 32)
if err != nil {
return 0, err
}
return uint32(i), nil
}
// ConvertUint64 turn a string into an uint64
func ConvertUint64(str string) (uint64, error) {
return strconv.ParseUint(str, 10, 64)
}
// FormatBool turns a boolean into a string
func FormatBool(value bool) string {
return strconv.FormatBool(value)
}
// FormatFloat32 turns a float32 into a string
func FormatFloat32(value float32) string {
return strconv.FormatFloat(float64(value), 'f', -1, 32)
}
// FormatFloat64 turns a float64 into a string
func FormatFloat64(value float64) string {
return strconv.FormatFloat(value, 'f', -1, 64)
}
// FormatInt8 turns an int8 into a string
func FormatInt8(value int8) string {
return strconv.FormatInt(int64(value), 10)
}
// FormatInt16 turns an int16 into a string
func FormatInt16(value int16) string {
return strconv.FormatInt(int64(value), 10)
}
// FormatInt32 turns an int32 into a string
func FormatInt32(value int32) string {
return strconv.Itoa(int(value))
}
// FormatInt64 turns an int64 into a string
func FormatInt64(value int64) string {
return strconv.FormatInt(value, 10)
}
// FormatUint8 turns an uint8 into a string
func FormatUint8(value uint8) string {
return strconv.FormatUint(uint64(value), 10)
}
// FormatUint16 turns an uint16 into a string
func FormatUint16(value uint16) string {
return strconv.FormatUint(uint64(value), 10)
}
// FormatUint32 turns an uint32 into a string
func FormatUint32(value uint32) string {
return strconv.FormatUint(uint64(value), 10)
}
// FormatUint64 turns an uint64 into a string
func FormatUint64(value uint64) string {
return strconv.FormatUint(value, 10)
}
-730
View File
@@ -1,730 +0,0 @@
package swag
import "time"
// This file was taken from the aws go sdk
// String returns a pointer to of the string value passed in.
func String(v string) *string {
return &v
}
// StringValue returns the value of the string pointer passed in or
// "" if the pointer is nil.
func StringValue(v *string) string {
if v != nil {
return *v
}
return ""
}
// StringSlice converts a slice of string values into a slice of
// string pointers
func StringSlice(src []string) []*string {
dst := make([]*string, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// StringValueSlice converts a slice of string pointers into a slice of
// string values
func StringValueSlice(src []*string) []string {
dst := make([]string, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// StringMap converts a string map of string values into a string
// map of string pointers
func StringMap(src map[string]string) map[string]*string {
dst := make(map[string]*string)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// StringValueMap converts a string map of string pointers into a string
// map of string values
func StringValueMap(src map[string]*string) map[string]string {
dst := make(map[string]string)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Bool returns a pointer to of the bool value passed in.
func Bool(v bool) *bool {
return &v
}
// BoolValue returns the value of the bool pointer passed in or
// false if the pointer is nil.
func BoolValue(v *bool) bool {
if v != nil {
return *v
}
return false
}
// BoolSlice converts a slice of bool values into a slice of
// bool pointers
func BoolSlice(src []bool) []*bool {
dst := make([]*bool, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// BoolValueSlice converts a slice of bool pointers into a slice of
// bool values
func BoolValueSlice(src []*bool) []bool {
dst := make([]bool, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// BoolMap converts a string map of bool values into a string
// map of bool pointers
func BoolMap(src map[string]bool) map[string]*bool {
dst := make(map[string]*bool)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// BoolValueMap converts a string map of bool pointers into a string
// map of bool values
func BoolValueMap(src map[string]*bool) map[string]bool {
dst := make(map[string]bool)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Int returns a pointer to of the int value passed in.
func Int(v int) *int {
return &v
}
// IntValue returns the value of the int pointer passed in or
// 0 if the pointer is nil.
func IntValue(v *int) int {
if v != nil {
return *v
}
return 0
}
// IntSlice converts a slice of int values into a slice of
// int pointers
func IntSlice(src []int) []*int {
dst := make([]*int, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// IntValueSlice converts a slice of int pointers into a slice of
// int values
func IntValueSlice(src []*int) []int {
dst := make([]int, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// IntMap converts a string map of int values into a string
// map of int pointers
func IntMap(src map[string]int) map[string]*int {
dst := make(map[string]*int)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// IntValueMap converts a string map of int pointers into a string
// map of int values
func IntValueMap(src map[string]*int) map[string]int {
dst := make(map[string]int)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Int32 returns a pointer to of the int32 value passed in.
func Int32(v int32) *int32 {
return &v
}
// Int32Value returns the value of the int32 pointer passed in or
// 0 if the pointer is nil.
func Int32Value(v *int32) int32 {
if v != nil {
return *v
}
return 0
}
// Int32Slice converts a slice of int32 values into a slice of
// int32 pointers
func Int32Slice(src []int32) []*int32 {
dst := make([]*int32, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Int32ValueSlice converts a slice of int32 pointers into a slice of
// int32 values
func Int32ValueSlice(src []*int32) []int32 {
dst := make([]int32, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Int32Map converts a string map of int32 values into a string
// map of int32 pointers
func Int32Map(src map[string]int32) map[string]*int32 {
dst := make(map[string]*int32)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Int32ValueMap converts a string map of int32 pointers into a string
// map of int32 values
func Int32ValueMap(src map[string]*int32) map[string]int32 {
dst := make(map[string]int32)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Int64 returns a pointer to of the int64 value passed in.
func Int64(v int64) *int64 {
return &v
}
// Int64Value returns the value of the int64 pointer passed in or
// 0 if the pointer is nil.
func Int64Value(v *int64) int64 {
if v != nil {
return *v
}
return 0
}
// Int64Slice converts a slice of int64 values into a slice of
// int64 pointers
func Int64Slice(src []int64) []*int64 {
dst := make([]*int64, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Int64ValueSlice converts a slice of int64 pointers into a slice of
// int64 values
func Int64ValueSlice(src []*int64) []int64 {
dst := make([]int64, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Int64Map converts a string map of int64 values into a string
// map of int64 pointers
func Int64Map(src map[string]int64) map[string]*int64 {
dst := make(map[string]*int64)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Int64ValueMap converts a string map of int64 pointers into a string
// map of int64 values
func Int64ValueMap(src map[string]*int64) map[string]int64 {
dst := make(map[string]int64)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Uint16 returns a pointer to of the uint16 value passed in.
func Uint16(v uint16) *uint16 {
return &v
}
// Uint16Value returns the value of the uint16 pointer passed in or
// 0 if the pointer is nil.
func Uint16Value(v *uint16) uint16 {
if v != nil {
return *v
}
return 0
}
// Uint16Slice converts a slice of uint16 values into a slice of
// uint16 pointers
func Uint16Slice(src []uint16) []*uint16 {
dst := make([]*uint16, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Uint16ValueSlice converts a slice of uint16 pointers into a slice of
// uint16 values
func Uint16ValueSlice(src []*uint16) []uint16 {
dst := make([]uint16, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Uint16Map converts a string map of uint16 values into a string
// map of uint16 pointers
func Uint16Map(src map[string]uint16) map[string]*uint16 {
dst := make(map[string]*uint16)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Uint16ValueMap converts a string map of uint16 pointers into a string
// map of uint16 values
func Uint16ValueMap(src map[string]*uint16) map[string]uint16 {
dst := make(map[string]uint16)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Uint returns a pointer to of the uint value passed in.
func Uint(v uint) *uint {
return &v
}
// UintValue returns the value of the uint pointer passed in or
// 0 if the pointer is nil.
func UintValue(v *uint) uint {
if v != nil {
return *v
}
return 0
}
// UintSlice converts a slice of uint values into a slice of
// uint pointers
func UintSlice(src []uint) []*uint {
dst := make([]*uint, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// UintValueSlice converts a slice of uint pointers into a slice of
// uint values
func UintValueSlice(src []*uint) []uint {
dst := make([]uint, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// UintMap converts a string map of uint values into a string
// map of uint pointers
func UintMap(src map[string]uint) map[string]*uint {
dst := make(map[string]*uint)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// UintValueMap converts a string map of uint pointers into a string
// map of uint values
func UintValueMap(src map[string]*uint) map[string]uint {
dst := make(map[string]uint)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Uint32 returns a pointer to of the uint32 value passed in.
func Uint32(v uint32) *uint32 {
return &v
}
// Uint32Value returns the value of the uint32 pointer passed in or
// 0 if the pointer is nil.
func Uint32Value(v *uint32) uint32 {
if v != nil {
return *v
}
return 0
}
// Uint32Slice converts a slice of uint32 values into a slice of
// uint32 pointers
func Uint32Slice(src []uint32) []*uint32 {
dst := make([]*uint32, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Uint32ValueSlice converts a slice of uint32 pointers into a slice of
// uint32 values
func Uint32ValueSlice(src []*uint32) []uint32 {
dst := make([]uint32, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Uint32Map converts a string map of uint32 values into a string
// map of uint32 pointers
func Uint32Map(src map[string]uint32) map[string]*uint32 {
dst := make(map[string]*uint32)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Uint32ValueMap converts a string map of uint32 pointers into a string
// map of uint32 values
func Uint32ValueMap(src map[string]*uint32) map[string]uint32 {
dst := make(map[string]uint32)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Uint64 returns a pointer to of the uint64 value passed in.
func Uint64(v uint64) *uint64 {
return &v
}
// Uint64Value returns the value of the uint64 pointer passed in or
// 0 if the pointer is nil.
func Uint64Value(v *uint64) uint64 {
if v != nil {
return *v
}
return 0
}
// Uint64Slice converts a slice of uint64 values into a slice of
// uint64 pointers
func Uint64Slice(src []uint64) []*uint64 {
dst := make([]*uint64, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Uint64ValueSlice converts a slice of uint64 pointers into a slice of
// uint64 values
func Uint64ValueSlice(src []*uint64) []uint64 {
dst := make([]uint64, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Uint64Map converts a string map of uint64 values into a string
// map of uint64 pointers
func Uint64Map(src map[string]uint64) map[string]*uint64 {
dst := make(map[string]*uint64)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Uint64ValueMap converts a string map of uint64 pointers into a string
// map of uint64 values
func Uint64ValueMap(src map[string]*uint64) map[string]uint64 {
dst := make(map[string]uint64)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Float32 returns a pointer to of the float32 value passed in.
func Float32(v float32) *float32 {
return &v
}
// Float32Value returns the value of the float32 pointer passed in or
// 0 if the pointer is nil.
func Float32Value(v *float32) float32 {
if v != nil {
return *v
}
return 0
}
// Float32Slice converts a slice of float32 values into a slice of
// float32 pointers
func Float32Slice(src []float32) []*float32 {
dst := make([]*float32, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Float32ValueSlice converts a slice of float32 pointers into a slice of
// float32 values
func Float32ValueSlice(src []*float32) []float32 {
dst := make([]float32, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Float32Map converts a string map of float32 values into a string
// map of float32 pointers
func Float32Map(src map[string]float32) map[string]*float32 {
dst := make(map[string]*float32)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Float32ValueMap converts a string map of float32 pointers into a string
// map of float32 values
func Float32ValueMap(src map[string]*float32) map[string]float32 {
dst := make(map[string]float32)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Float64 returns a pointer to of the float64 value passed in.
func Float64(v float64) *float64 {
return &v
}
// Float64Value returns the value of the float64 pointer passed in or
// 0 if the pointer is nil.
func Float64Value(v *float64) float64 {
if v != nil {
return *v
}
return 0
}
// Float64Slice converts a slice of float64 values into a slice of
// float64 pointers
func Float64Slice(src []float64) []*float64 {
dst := make([]*float64, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Float64ValueSlice converts a slice of float64 pointers into a slice of
// float64 values
func Float64ValueSlice(src []*float64) []float64 {
dst := make([]float64, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Float64Map converts a string map of float64 values into a string
// map of float64 pointers
func Float64Map(src map[string]float64) map[string]*float64 {
dst := make(map[string]*float64)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Float64ValueMap converts a string map of float64 pointers into a string
// map of float64 values
func Float64ValueMap(src map[string]*float64) map[string]float64 {
dst := make(map[string]float64)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Time returns a pointer to of the time.Time value passed in.
func Time(v time.Time) *time.Time {
return &v
}
// TimeValue returns the value of the time.Time pointer passed in or
// time.Time{} if the pointer is nil.
func TimeValue(v *time.Time) time.Time {
if v != nil {
return *v
}
return time.Time{}
}
// TimeSlice converts a slice of time.Time values into a slice of
// time.Time pointers
func TimeSlice(src []time.Time) []*time.Time {
dst := make([]*time.Time, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// TimeValueSlice converts a slice of time.Time pointers into a slice of
// time.Time values
func TimeValueSlice(src []*time.Time) []time.Time {
dst := make([]time.Time, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// TimeMap converts a string map of time.Time values into a string
// map of time.Time pointers
func TimeMap(src map[string]time.Time) map[string]*time.Time {
dst := make(map[string]*time.Time)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// TimeValueMap converts a string map of time.Time pointers into a string
// map of time.Time values
func TimeValueMap(src map[string]*time.Time) map[string]time.Time {
dst := make(map[string]time.Time)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
+43 -16
View File
@@ -12,20 +12,47 @@
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package swag contains a bunch of helper functions for go-openapi and go-swagger projects.
You may also use it standalone for your projects.
- convert between value and pointers for builtin types
- convert from string to builtin types (wraps strconv)
- fast json concatenation
- search in path
- load from file or http
- name mangling
This repo has only few dependencies outside of the standard library:
- YAML utilities depend on gopkg.in/yaml.v2
*/
// Package swag contains a bunch of helper functions for go-openapi and go-swagger projects.
//
// You may also use it standalone for your projects.
//
// 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.
//
// Child modules will continue to evolve or some new ones may be added in the future.
//
// # Modules
//
// - [cmdutils] utilities to work with CLIs
//
// - [conv] type conversion utilities
//
// - [fileutils] file utilities
//
// - [jsonname] JSON utilities
//
// - [jsonutils] JSON utilities
//
// - [loading] file loading
//
// - [mangling] safe name generation
//
// - [netutils] networking utilities
//
// - [stringutils] `string` utilities
//
// - [typeutils] `go` types utilities
//
// - [yamlutils] YAML utilities
//
// # Dependencies
//
// This repo has a few dependencies outside of the standard library:
//
// - YAML utilities depend on [go.yaml.in/yaml/v3]
package swag
//go:generate mockery
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+21
View File
@@ -0,0 +1,21 @@
// 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 fileutils exposes utilities to deal with files and paths.
//
// Currently, there is:
// - [File] to represent an abstraction of an uploaded file.
// For instance, this is used by [github.com/go-openapi/runtime.File].
// - path search utilities (e.g. finding packages in the GO search path)
package fileutils
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package swag
package fileutils
import "mime/multipart"
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package swag
package fileutils
import (
"os"
@@ -21,10 +21,8 @@ import (
"strings"
)
const (
// GOPATHKey represents the env key for gopath
GOPATHKey = "GOPATH"
)
// GOPATHKey represents the env key for gopath
const GOPATHKey = "GOPATH"
// FindInSearchPath finds a package in a provided lists of paths
func FindInSearchPath(searchPath, pkg string) string {
@@ -40,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 == "" {
+44
View File
@@ -0,0 +1,44 @@
// 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 swag
import "github.com/go-openapi/swag/fileutils"
// GOPATHKey represents the env key for gopath
//
// Deprecated: use [fileutils.GOPATHKey] instead.
const GOPATHKey = fileutils.GOPATHKey
// File represents an uploaded file.
//
// Deprecated: use [fileutils.File] instead.
type File = fileutils.File
// FindInSearchPath finds a package in a provided lists of paths.
//
// Deprecated: use [fileutils.FindInSearchPath] instead.
func FindInSearchPath(searchPath, pkg string) string {
return fileutils.FindInSearchPath(searchPath, pkg)
}
// FindInGoSearchPath finds a package in the $GOPATH:$GOROOT
//
// Deprecated: use [fileutils.FindInGoSearchPath] instead.
func FindInGoSearchPath(pkg string) string { return fileutils.FindInGoSearchPath(pkg) }
// FullGoSearchPath gets the search paths for finding packages
//
// Deprecated: use [fileutils.FullGoSearchPath] instead.
func FullGoSearchPath() string { return fileutils.FullGoSearchPath() }
+20
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
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=
-202
View File
@@ -1,202 +0,0 @@
// 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 swag
import (
"sort"
"strings"
"sync"
)
var (
// commonInitialisms are common acronyms that are kept as whole uppercased words.
commonInitialisms *indexOfInitialisms
// initialisms is a slice of sorted initialisms
initialisms []string
// a copy of initialisms pre-baked as []rune
initialismsRunes [][]rune
initialismsUpperCased [][]rune
isInitialism func(string) bool
maxAllocMatches int
)
func init() {
// Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
configuredInitialisms := map[string]bool{
"ACL": true,
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTPS": true,
"HTTP": true,
"ID": true,
"IP": true,
"IPv4": true,
"IPv6": true,
"JSON": true,
"LHS": true,
"OAI": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SQL": true,
"SSH": true,
"TCP": true,
"TLS": true,
"TTL": true,
"UDP": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XMPP": true,
"XSRF": true,
"XSS": true,
}
// a thread-safe index of initialisms
commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
initialisms = commonInitialisms.sorted()
initialismsRunes = asRunes(initialisms)
initialismsUpperCased = asUpperCased(initialisms)
maxAllocMatches = maxAllocHeuristic(initialismsRunes)
// a test function
isInitialism = commonInitialisms.isInitialism
}
func asRunes(in []string) [][]rune {
out := make([][]rune, len(in))
for i, initialism := range in {
out[i] = []rune(initialism)
}
return out
}
func asUpperCased(in []string) [][]rune {
out := make([][]rune, len(in))
for i, initialism := range in {
out[i] = []rune(upper(trim(initialism)))
}
return out
}
func maxAllocHeuristic(in [][]rune) int {
heuristic := make(map[rune]int)
for _, initialism := range in {
heuristic[initialism[0]]++
}
var maxAlloc int
for _, val := range heuristic {
if val > maxAlloc {
maxAlloc = val
}
}
return maxAlloc
}
// AddInitialisms add additional initialisms
func AddInitialisms(words ...string) {
for _, word := range words {
// commonInitialisms[upper(word)] = true
commonInitialisms.add(upper(word))
}
// sort again
initialisms = commonInitialisms.sorted()
initialismsRunes = asRunes(initialisms)
initialismsUpperCased = asUpperCased(initialisms)
}
// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms.
// Since go1.9, this may be implemented with sync.Map.
type indexOfInitialisms struct {
sortMutex *sync.Mutex
index *sync.Map
}
func newIndexOfInitialisms() *indexOfInitialisms {
return &indexOfInitialisms{
sortMutex: new(sync.Mutex),
index: new(sync.Map),
}
}
func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms {
m.sortMutex.Lock()
defer m.sortMutex.Unlock()
for k, v := range initial {
m.index.Store(k, v)
}
return m
}
func (m *indexOfInitialisms) isInitialism(key string) bool {
_, ok := m.index.Load(key)
return ok
}
func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
m.index.Store(key, true)
return m
}
func (m *indexOfInitialisms) sorted() (result []string) {
m.sortMutex.Lock()
defer m.sortMutex.Unlock()
m.index.Range(func(key, _ interface{}) bool {
k := key.(string)
result = append(result, k)
return true
})
sort.Sort(sort.Reverse(byInitialism(result)))
return
}
type byInitialism []string
func (s byInitialism) Len() int {
return len(s)
}
func (s byInitialism) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s byInitialism) Less(i, j int) bool {
if len(s[i]) != len(s[j]) {
return len(s[i]) < len(s[j])
}
return strings.Compare(s[i], s[j]) > 0
}
-312
View File
@@ -1,312 +0,0 @@
// 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 swag
import (
"bytes"
"encoding/json"
"log"
"reflect"
"strings"
"sync"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
)
// nullJSON represents a JSON object with null type
var nullJSON = []byte("null")
// DefaultJSONNameProvider the default cache for types
var DefaultJSONNameProvider = NewNameProvider()
const comma = byte(',')
var closers map[byte]byte
func init() {
closers = map[byte]byte{
'{': '}',
'[': ']',
}
}
type ejMarshaler interface {
MarshalEasyJSON(w *jwriter.Writer)
}
type ejUnmarshaler interface {
UnmarshalEasyJSON(w *jlexer.Lexer)
}
// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaler
// so it takes the fastest option available.
func WriteJSON(data interface{}) ([]byte, error) {
if d, ok := data.(ejMarshaler); ok {
jw := new(jwriter.Writer)
d.MarshalEasyJSON(jw)
return jw.BuildBytes()
}
if d, ok := data.(json.Marshaler); ok {
return d.MarshalJSON()
}
return json.Marshal(data)
}
// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaler
// so it takes the fastest option available
func ReadJSON(data []byte, value interface{}) error {
trimmedData := bytes.Trim(data, "\x00")
if d, ok := value.(ejUnmarshaler); ok {
jl := &jlexer.Lexer{Data: trimmedData}
d.UnmarshalEasyJSON(jl)
return jl.Error()
}
if d, ok := value.(json.Unmarshaler); ok {
return d.UnmarshalJSON(trimmedData)
}
return json.Unmarshal(trimmedData, value)
}
// DynamicJSONToStruct converts an untyped json structure into a struct
func DynamicJSONToStruct(data interface{}, target interface{}) error {
// TODO: convert straight to a json typed map (mergo + iterate?)
b, err := WriteJSON(data)
if err != nil {
return err
}
return ReadJSON(b, target)
}
// ConcatJSON concatenates multiple json objects efficiently
func ConcatJSON(blobs ...[]byte) []byte {
if len(blobs) == 0 {
return nil
}
last := len(blobs) - 1
for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
// strips trailing null objects
last--
if last < 0 {
// there was nothing but "null"s or nil...
return nil
}
}
if last == 0 {
return blobs[0]
}
var opening, closing byte
var idx, a int
buf := bytes.NewBuffer(nil)
for i, b := range blobs[:last+1] {
if b == nil || bytes.Equal(b, nullJSON) {
// a null object is in the list: skip it
continue
}
if len(b) > 0 && opening == 0 { // is this an array or an object?
opening, closing = b[0], closers[b[0]]
}
if opening != '{' && opening != '[' {
continue // don't know how to concatenate non container objects
}
if len(b) < 3 { // yep empty but also the last one, so closing this thing
if i == last && a > 0 {
if err := buf.WriteByte(closing); err != nil {
log.Println(err)
}
}
continue
}
idx = 0
if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
if err := buf.WriteByte(comma); err != nil {
log.Println(err)
}
idx = 1 // this is not the first or the last so we want to drop the leading bracket
}
if i != last { // not the last one, strip brackets
if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
log.Println(err)
}
} else { // last one, strip only the leading bracket
if _, err := buf.Write(b[idx:]); err != nil {
log.Println(err)
}
}
a++
}
// somehow it ended up being empty, so provide a default value
if buf.Len() == 0 {
if err := buf.WriteByte(opening); err != nil {
log.Println(err)
}
if err := buf.WriteByte(closing); err != nil {
log.Println(err)
}
}
return buf.Bytes()
}
// ToDynamicJSON turns an object into a properly JSON typed structure
func ToDynamicJSON(data interface{}) interface{} {
// TODO: convert straight to a json typed map (mergo + iterate?)
b, err := json.Marshal(data)
if err != nil {
log.Println(err)
}
var res interface{}
if err := json.Unmarshal(b, &res); err != nil {
log.Println(err)
}
return res
}
// FromDynamicJSON turns an object into a properly JSON typed structure
func FromDynamicJSON(data, target interface{}) error {
b, err := json.Marshal(data)
if err != nil {
log.Println(err)
}
return json.Unmarshal(b, target)
}
// NameProvider represents an object capable of translating from go property names
// to json property names
// This type is thread-safe.
type NameProvider struct {
lock *sync.Mutex
index map[reflect.Type]nameIndex
}
type nameIndex struct {
jsonNames map[string]string
goNames map[string]string
}
// NewNameProvider creates a new name provider
func NewNameProvider() *NameProvider {
return &NameProvider{
lock: &sync.Mutex{},
index: make(map[reflect.Type]nameIndex),
}
}
func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
for i := 0; i < tpe.NumField(); i++ {
targetDes := tpe.Field(i)
if targetDes.PkgPath != "" { // unexported
continue
}
if targetDes.Anonymous { // walk embedded structures tree down first
buildnameIndex(targetDes.Type, idx, reverseIdx)
continue
}
if tag := targetDes.Tag.Get("json"); tag != "" {
parts := strings.Split(tag, ",")
if len(parts) == 0 {
continue
}
nm := parts[0]
if nm == "-" {
continue
}
if nm == "" { // empty string means we want to use the Go name
nm = targetDes.Name
}
idx[nm] = targetDes.Name
reverseIdx[targetDes.Name] = nm
}
}
}
func newNameIndex(tpe reflect.Type) nameIndex {
var idx = make(map[string]string, tpe.NumField())
var reverseIdx = make(map[string]string, tpe.NumField())
buildnameIndex(tpe, idx, reverseIdx)
return nameIndex{jsonNames: idx, goNames: reverseIdx}
}
// GetJSONNames gets all the json property names for a type
func (n *NameProvider) GetJSONNames(subject interface{}) []string {
n.lock.Lock()
defer n.lock.Unlock()
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
names, ok := n.index[tpe]
if !ok {
names = n.makeNameIndex(tpe)
}
res := make([]string, 0, len(names.jsonNames))
for k := range names.jsonNames {
res = append(res, k)
}
return res
}
// GetJSONName gets the json name for a go property name
func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
return n.GetJSONNameForType(tpe, name)
}
// GetJSONNameForType gets the json name for a go property name on a given type
func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
n.lock.Lock()
defer n.lock.Unlock()
names, ok := n.index[tpe]
if !ok {
names = n.makeNameIndex(tpe)
}
nme, ok := names.goNames[name]
return nme, ok
}
func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
names := newNameIndex(tpe)
n.index[tpe] = names
return names
}
// GetGoName gets the go name for a json property name
func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
return n.GetGoNameForType(tpe, name)
}
// GetGoNameForType gets the go name for a given type for a json property name
func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
n.lock.Lock()
defer n.lock.Unlock()
names, ok := n.index[tpe]
if !ok {
names = n.makeNameIndex(tpe)
}
nme, ok := names.jsonNames[name]
return nme, ok
}
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+16
View File
@@ -0,0 +1,16 @@
// 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 jsonname is a provider of json property names from go properties.
package jsonname

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