From ff5d498916517f92e179e9cdd17940d3e1fa29a8 Mon Sep 17 00:00:00 2001 From: thediveo Date: Sat, 3 Jan 2026 15:38:41 +0000 Subject: [PATCH 1/2] chore: workflow, Makefile Signed-off-by: thediveo --- .github/workflows/buildandtest.yaml | 4 ++-- Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/buildandtest.yaml b/.github/workflows/buildandtest.yaml index 35e0abf..e966b98 100644 --- a/.github/workflows/buildandtest.yaml +++ b/.github/workflows/buildandtest.yaml @@ -18,13 +18,13 @@ jobs: steps: - name: Set up Go ${{matrix.go}} - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v4 + uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # pin@v5 with: go-version: ${{matrix.go}} id: go - name: Check out code into the Go module directory - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4 - name: Test run: go test -v -p=1 -race ./... diff --git a/Makefile b/Makefile index bb0ce6d..7b69313 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help clean coverage pkgsite report test vuln chores +.PHONY: help clean coverage report test help: ## list available targets @# Shamelessly stolen from Gomega's Makefile From 2e2e5546215a1a6f14cdc87b50119fc72c50cf2a Mon Sep 17 00:00:00 2001 From: thediveo Date: Sat, 3 Jan 2026 16:11:46 +0000 Subject: [PATCH 2/2] refact/feat: GetValue/GetSliceValue methods; using predefined comparable instead of constraint.Ordered; Signed-off-by: thediveo --- Makefile | 19 ------ README.md | 25 +------ completion.go | 3 +- completion_test.go | 2 +- example_external_test.go | 26 +++---- example_nodefault_test.go | 2 +- example_slice_test.go | 2 +- example_test.go | 2 +- flag.go | 60 +++++++++++------ flag_test.go | 21 +++++- go.mod | 34 +++++----- go.sum | 138 ++++++++++++++++++-------------------- mapper.go | 10 ++- value_scalar.go | 3 +- value_slice.go | 5 +- 15 files changed, 166 insertions(+), 186 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 7b69313..0000000 --- a/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -.PHONY: help clean coverage report test - -help: ## list available targets - @# Shamelessly stolen from Gomega's Makefile - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-16s\033[0m %s\n", $$1, $$2}' - -clean: ## cleans up build and testing artefacts - rm -f coverage.* - -test: ## run unit tests - go test -v -p=1 -race ./... - -report: ## run goreportcard-cli on this module -# from ghcr.io/thediveo/devcontainer-features/goreportcard - goreportcard-cli -v ./.. - -coverage: ## gathers coverage and updates README badge -# from ghcr.io/thediveo/devcontainer-features/gocover - gocover diff --git a/README.md b/README.md index 4b05f62..d21e9f6 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ enumeration values either with a single flag `--mode=foo,bar` or multiple flag calls, such as `--mode=foo --mode=bar`. Application programmers then simply deal with enumeration values in form of -uints (or ints, _erm_, anything that satisfies `constraints.Ordered`s), +uints (or ints, _erm_, anything that satisfies `comparable`s), liberated from parsing strings and validating enumeration flags. For devcontainer instructions, please see the [section "DevContainer" @@ -76,7 +76,7 @@ import ( ) // ① Define your new enum flag type. It can be derived from enumflag.Flag, -// but it doesn't need to be as long as it satisfies constraints.Ordered. +// but it doesn't need to be as long as it satisfies comparable. type FooMode enumflag.Flag // ② Define the enumeration values for FooMode. @@ -306,7 +306,7 @@ import ( ) // ① Define your new enum flag type. It can be derived from enumflag.Flag, -// but it doesn't need to be as long as it satisfies constraints.Ordered. +// but it doesn't need to be as long as it satisfies comparable. type MooMode enumflag.Flag // ② Define the enumeration values for FooMode. @@ -357,25 +357,6 @@ func Example_slice() { 2. in VSCode: Ctrl+Shift+P, "Dev Containers: Open Workspace in Container..." 3. select `enumflag.code-workspace` and off you go... -## VSCode Tasks - -The included `enumflag.code-workspace` defines the following tasks: - -- **Build workspace** task: builds all, including the shared library test - plugin. - -- **Run all tests with coverage** task: does what it says on the tin and runs - all tests with coverage. - -## Make Targets - -- `make`: lists available targets. -- `make test`: runs all tests. -- `make coverage`: deprecated, use the `gocover` CLI command in the devcontainer - instead. -- `make report`: deprecated, use the `goreportcard-cli` CLI command in the - devcontainer instead. - ## Contributing Please see [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/completion.go b/completion.go index a4dcb03..06958ef 100644 --- a/completion.go +++ b/completion.go @@ -16,7 +16,6 @@ package enumflag import ( "github.com/spf13/cobra" - "golang.org/x/exp/constraints" ) // Help maps enumeration values to their corresponding help descriptions. These @@ -24,7 +23,7 @@ import ( // value prefix. The reason is that enumflag will automatically register the // correct (erm, “complete”) completion text. Please note that it isn't // necessary to supply any help texts in order to register enum flag completion. -type Help[E constraints.Ordered] map[E]string +type Help[E comparable] map[E]string // Completor tells cobra how to complete a flag. See also cobra's [dynamic flag // completion] documentation. diff --git a/completion_test.go b/completion_test.go index b16d481..a049904 100644 --- a/completion_test.go +++ b/completion_test.go @@ -19,12 +19,12 @@ import ( "os" "os/exec" "path/filepath" + "slices" "syscall" "time" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" - "golang.org/x/exp/slices" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" diff --git a/example_external_test.go b/example_external_test.go index 1720265..deae744 100644 --- a/example_external_test.go +++ b/example_external_test.go @@ -2,34 +2,26 @@ package enumflag_test import ( "fmt" - "os" + "log/slog" - log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/thediveo/enumflag/v2" ) -func init() { - log.SetOutput(os.Stdout) -} - func Example_external() { // ①+② skip "define your own enum flag type" and enumeration values, as we // already have a 3rd party one. // ③ Map 3rd party enumeration values to their textual representations - var LoglevelIds = map[log.Level][]string{ - log.TraceLevel: {"trace"}, - log.DebugLevel: {"debug"}, - log.InfoLevel: {"info"}, - log.WarnLevel: {"warning", "warn"}, - log.ErrorLevel: {"error"}, - log.FatalLevel: {"fatal"}, - log.PanicLevel: {"panic"}, + var LoglevelIds = map[slog.Level][]string{ + slog.LevelDebug: {"debug"}, + slog.LevelInfo: {"info"}, + slog.LevelWarn: {"warning", "warn"}, + slog.LevelError: {"error"}, } // ④ Define your enum flag value and set the your logging default value. - var loglevel log.Level = log.WarnLevel + var loglevel = slog.LevelWarn rootCmd := &cobra.Command{ Run: func(cmd *cobra.Command, _ []string) { @@ -49,6 +41,6 @@ func Example_external() { rootCmd.SetArgs([]string{"--log", "debug"}) _ = rootCmd.Execute() // Output: - // logging level is: 3="warning" - // logging level is: 5="debug" + // logging level is: 4="warning" + // logging level is: -4="debug" } diff --git a/example_nodefault_test.go b/example_nodefault_test.go index 040fd2b..57e7197 100644 --- a/example_nodefault_test.go +++ b/example_nodefault_test.go @@ -9,7 +9,7 @@ import ( ) // ① Define your new enum flag type. It can be derived from enumflag.Flag, -// but it doesn't need to be as long as it satisfies constraints.Ordered. +// but it doesn't need to be as long as it satisfies comparable. type BarMode enumflag.Flag // ② Define the enumeration values for BarMode. diff --git a/example_slice_test.go b/example_slice_test.go index 3e77ca3..e68b0ef 100644 --- a/example_slice_test.go +++ b/example_slice_test.go @@ -9,7 +9,7 @@ import ( ) // ① Define your new enum flag type. It can be derived from enumflag.Flag, -// but it doesn't need to be as long as it satisfies constraints.Ordered. +// but it doesn't need to be as long as it satisfies comparable. type MooMode enumflag.Flag // ② Define the enumeration values for FooMode. diff --git a/example_test.go b/example_test.go index b3a204c..ae706f4 100644 --- a/example_test.go +++ b/example_test.go @@ -9,7 +9,7 @@ import ( ) // ① Define your new enum flag type. It can be derived from enumflag.Flag, -// but it doesn't need to be as long as it satisfies constraints.Ordered. +// but it doesn't need to be as long as it satisfies comparable. type FooMode enumflag.Flag // ② Define the enumeration values for FooMode. diff --git a/flag.go b/flag.go index 7db757e..c59e931 100644 --- a/flag.go +++ b/flag.go @@ -18,7 +18,6 @@ import ( "fmt" "github.com/spf13/cobra" - "golang.org/x/exp/constraints" ) // Flag represents a CLI (enumeration) flag which can take on only a single @@ -31,7 +30,9 @@ import ( // However, applications don't need to base their own enum types on Flag. The // only requirement for user-defined enumeration flags is that they must be // (“somewhat”) compatible with the Flag type, or more precise: user-defined -// enumerations must satisfy [constraints.Ordered]. +// enumerations must satisfy the predeclared type identifier [comparable]. +// +// [comparable]: https://go.dev/blog/comparable type Flag uint // EnumCaseSensitivity specifies whether the textual representations of enum @@ -45,12 +46,11 @@ const ( EnumCaseSensitive EnumCaseSensitivity = true ) -// EnumFlagValue wraps a user-defined enum type value satisfying -// [constraints.Ordered] or [][constraints.Ordered]. It implements the -// [github.com/spf13/pflag.Value] interface, so the user-defined enum type value -// can directly be used with the fine pflag drop-in package for Golang CLI -// flags. -type EnumFlagValue[E constraints.Ordered] struct { +// EnumFlagValue wraps a user-defined enum type value satisfying comparable or +// []comparable. It implements the [github.com/spf13/pflag.Value] interface, so +// the user-defined enum type value can directly be used with the fine pflag +// drop-in package for Golang CLI flags. +type EnumFlagValue[E comparable] struct { value enumValue[E] // enum value of a user-defined enum scalar or slice type. enumtype string // user-friendly name of the user-defined enum type. names enumMapper[E] // enum value names. @@ -63,26 +63,26 @@ type EnumFlagValue[E constraints.Ordered] struct { // code”: by just moving the interface type from the source file with the struct // types to the source file with the consumer we achieve immediate Go // perfectness! Strike! -type enumValue[E constraints.Ordered] interface { +type enumValue[E comparable] interface { Get() any Set(val string, names enumMapper[E]) error String(names enumMapper[E]) string NewCompletor(enums EnumIdentifiers[E], help Help[E]) Completor } -// New wraps a given enum variable (satisfying [constraints.Ordered]) so that it -// can be used as a flag Value with [github.com/spf13/pflag.Var] and -// [github.com/spf13/pflag.VarP]. In case no default enum value should be set -// and therefore no default shown in [spf13/cobra], use [NewWithoutDefault] -// instead. +// New wraps a given enum variable (satisfying the predeclared type identifier +// comparable) so that it can be used as a flag Value with +// [github.com/spf13/pflag.Var] and [github.com/spf13/pflag.VarP]. In case no +// default enum value should be set and therefore no default shown in +// [spf13/cobra], use [NewWithoutDefault] instead. // // [spf13/cobra]: https://github.com/spf13/cobra -func New[E constraints.Ordered](flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] { +func New[E comparable](flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] { return new("New", flag, typename, mapping, sensitivity, false) } -// NewWithoutDefault wraps a given enum variable (satisfying -// [constraints.Ordered]) so that it can be used as a flag Value with +// NewWithoutDefault wraps a given enum variable (satisfying the predeclared +// type identifier comparable) so that it can be used as a flag Value with // [github.com/spf13/pflag.Var] and [github.com/spf13/pflag.VarP]. Please note // that the zero enum value must not be mapped and thus not be assigned to any // enum value textual representation. @@ -91,14 +91,14 @@ func New[E constraints.Ordered](flag *E, typename string, mapping EnumIdentifier // created with NewWithoutDefault. // // [spf13/cobra]: https://github.com/spf13/cobra -func NewWithoutDefault[E constraints.Ordered](flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] { +func NewWithoutDefault[E comparable](flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] { return new("NewWithoutDefault", flag, typename, mapping, sensitivity, true) } // new returns a new enum variable to be used with pflag.Var and pflag.VarP. -func new[E constraints.Ordered](ctor string, flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity, nodefault bool) *EnumFlagValue[E] { +func new[E comparable](ctor string, flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity, nodefault bool) *EnumFlagValue[E] { if flag == nil { - panic(fmt.Sprintf("%s requires flag to be a non-nil pointer to an enum value satisfying constraints.Ordered", ctor)) + panic(fmt.Sprintf("%s requires flag to be a non-nil pointer to an enum value satisfying comparable", ctor)) } if mapping == nil { panic(fmt.Sprintf("%s requires mapping not to be nil", ctor)) @@ -110,10 +110,10 @@ func new[E constraints.Ordered](ctor string, flag *E, typename string, mapping E } } -// NewSlice wraps a given enum slice variable (satisfying [constraints.Ordered]) +// NewSlice wraps a given enum slice variable (satisfying [comparable]) // so that it can be used as a flag Value with [github.com/spf13/pflag.Var] and // [github.com/spf13/pflag.VarP]. -func NewSlice[E constraints.Ordered](flag *[]E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] { +func NewSlice[E comparable](flag *[]E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] { if flag == nil { panic("NewSlice requires flag to be a non-nil pointer to an enum value slice satisfying []any") } @@ -154,3 +154,19 @@ func (e *EnumFlagValue[E]) RegisterCompletion(cmd *cobra.Command, name string, h return cmd.RegisterFlagCompletionFunc( name, e.value.NewCompletor(e.names.Mapping(), help)) } + +// GetValue returns the (scalar) enum value of type E, otherwise it returns the +// zero value for type E. +func (e *EnumFlagValue[E]) GetValue() (v E) { + ev := e.Get() // returns E, not *E + v, _ = ev.(E) + return +} + +// GetSliceValue returns the slice enum value of type []E, otherwise it returns +// the zero value for type []E. +func (e *EnumFlagValue[E]) GetSliceValue() (v []E) { + ev := e.Get() // returns []E, not *[]E + v, _ = ev.([]E) + return +} diff --git a/flag_test.go b/flag_test.go index 2a82a61..1e8bce5 100644 --- a/flag_test.go +++ b/flag_test.go @@ -15,9 +15,10 @@ package enumflag import ( + "github.com/spf13/cobra" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/spf13/cobra" ) var _ = Describe("flag", func() { @@ -60,6 +61,24 @@ var _ = Describe("flag", func() { }) + Context("retrieving the enum value", func() { + + It("succeeds for scalar", func() { + var foomode = fmBar + val := New(&foomode, "mode", FooModeIdentifiersTest, EnumCaseSensitive) + Expect(val.GetValue()).To(Equal(fmBar)) + Expect(val.GetSliceValue()).To(BeZero()) + }) + + It("succeeds for slices", func() { + var foomodes = []FooModeTest{fmBar} + val := NewSlice(&foomodes, "mode", FooModeIdentifiersTest, EnumCaseSensitive) + Expect(val.GetValue()).To(BeZero()) + Expect(val.GetSliceValue()).To(ConsistOf(fmBar)) + }) + + }) + When("passing nil", func() { It("panics", func() { diff --git a/go.mod b/go.mod index 5ec3736..9b38007 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,32 @@ module github.com/thediveo/enumflag/v2 -go 1.22.0 +go 1.23.0 toolchain go1.23.4 require ( - github.com/onsi/ginkgo/v2 v2.22.2 - github.com/onsi/gomega v1.36.2 - github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.1 + github.com/onsi/ginkgo/v2 v2.27.3 + github.com/onsi/gomega v1.38.3 + github.com/spf13/cobra v1.10.2 ) require ( - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect - golang.org/x/tools v0.28.0 // indirect + github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/mod v0.27.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/tools v0.36.0 // indirect ) require ( - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/thediveo/success v1.0.2 - golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + github.com/spf13/pflag v1.0.9 // indirect + github.com/thediveo/success v1.0.3 + golang.org/x/net v0.43.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect ) diff --git a/go.sum b/go.sum index 05b3102..1266d7d 100644 --- a/go.sum +++ b/go.sum @@ -1,83 +1,79 @@ -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= -github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA= -github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= +github.com/onsi/ginkgo/v2 v2.27.3 h1:ICsZJ8JoYafeXFFlFAG75a7CxMsJHwgKwtO+82SE9L8= +github.com/onsi/ginkgo/v2 v2.27.3/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM= +github.com/onsi/gomega v1.38.3/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/thediveo/success v1.0.1 h1:NVwUOwKUwaN8szjkJ+vsiM2L3sNBFscldoDJ2g2tAPg= -github.com/thediveo/success v1.0.1/go.mod h1:AZ8oUArgbIsCuDEWrzWNQHdKnPbDOLQsWOFj9ynwLt0= -github.com/thediveo/success v1.0.2 h1:w+r3RbSjLmd7oiNnlCblfGqItcsaShcuAorRVh/+0xk= -github.com/thediveo/success v1.0.2/go.mod h1:hdPJB77k70w764lh8uLUZgNhgeTl3DYeZ4d4bwMO2CU= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588= -golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/thediveo/success v1.0.3 h1:jaBpZ5ETfmCo9U3CRDtWPhtXQg3iW3beZH4ioLMR5RQ= +github.com/thediveo/success v1.0.3/go.mod h1:K+8SXrNPdonCYg4iCTYGQ6dCvqjGiTtLs5ZTB5eEKTg= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/mapper.go b/mapper.go index 86f1b14..eb28620 100644 --- a/mapper.go +++ b/mapper.go @@ -16,11 +16,9 @@ package enumflag import ( "fmt" + "slices" "sort" "strings" - - "golang.org/x/exp/constraints" - "golang.org/x/exp/slices" ) // EnumIdentifiers maps enumeration values to their corresponding textual @@ -29,18 +27,18 @@ import ( // representation (identifier). If more than one textual representation exists // for the same enumeration value, then the first textual representation is // considered to be the canonical one. -type EnumIdentifiers[E constraints.Ordered] map[E][]string +type EnumIdentifiers[E comparable] map[E][]string // enumMapper is an optionally case insensitive map from enum values to their // corresponding textual representations. -type enumMapper[E constraints.Ordered] struct { +type enumMapper[E comparable] struct { m EnumIdentifiers[E] sensitivity EnumCaseSensitivity } // newEnumMapper returns a new enumMapper for the given mapping and case // sensitivity or insensitivity. -func newEnumMapper[E constraints.Ordered](mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) enumMapper[E] { +func newEnumMapper[E comparable](mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) enumMapper[E] { return enumMapper[E]{ m: mapping, sensitivity: sensitivity, diff --git a/value_scalar.go b/value_scalar.go index bbf5f2f..454c4a9 100644 --- a/value_scalar.go +++ b/value_scalar.go @@ -16,7 +16,6 @@ package enumflag import ( "github.com/spf13/cobra" - "golang.org/x/exp/constraints" ) // unknown is the textual representation of an unknown enum value, that is, when @@ -26,7 +25,7 @@ const unknown = "" // enumScalar represents a mutable, single enumeration value that can be // retrieved, set, and stringified. -type enumScalar[E constraints.Ordered] struct { +type enumScalar[E comparable] struct { v *E nodefault bool // opts in to accepting a zero enum value as the "none" } diff --git a/value_slice.go b/value_slice.go index 2ec54c3..4eb3242 100644 --- a/value_slice.go +++ b/value_slice.go @@ -15,16 +15,15 @@ package enumflag import ( + "slices" "strings" "github.com/spf13/cobra" - "golang.org/x/exp/constraints" - "golang.org/x/exp/slices" ) // enumSlice represents a slice of enumeration values that can be retrieved, // set, and stringified. -type enumSlice[E constraints.Ordered] struct { +type enumSlice[E comparable] struct { v *[]E merge bool // replace the complete slice or merge values? }