Skip to content

Setting: enum

Definition

The Go language doesn't explicit define enums. In the context of Goverter an enum type is defined as a named type with an underlying type of (float, string, or integer) having at least one constant defined in the same package.

enum

enum [yes|no] can be defined as CLI argument or converter comment. enum is enabled per default.

enum allows you to disable enum support in goverter.

Example (click me)
go
package example

import (
	"time"
)

// goverter:converter
// goverter:enum no
type Converter interface {
	Convert(MyDuration) time.Duration
}

type MyDuration int64

const (
	Nanoseconds  MyDuration = 1
	Microseconds MyDuration = 1000 * Nanoseconds
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	disable "github.com/jmattheis/goverter/example/enum/disable"
	"time"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source disable.MyDuration) time.Duration {
	return time.Duration(source)
}

enum:unknown ACTION

enum:unknown ACTION|KEY can be defined as CLI argument, converter comment or method comment. This setting is inheritable.

Define what happens on an invalid or unexpected enum value.

enum:unknown @error returns an error in the default case of the switch statement.

Example (click me)
go
package example

import (
	"github.com/jmattheis/goverter/example/enum/unknown/input"
	"github.com/jmattheis/goverter/example/enum/unknown/output"
)

// goverter:converter
// goverter:enum:unknown @error
type Converter interface {
	Convert(input.Color) (output.Color, error)
}
go
package input

type Color int
const (
    Green Color = iota
    Blue
    Red
)
go
package output

type Color string
const (
    Green Color = "green"
    Blue  Color = "blue"
    Red   Color = "red"
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	"fmt"
	input "github.com/jmattheis/goverter/example/enum/unknown/input"
	output "github.com/jmattheis/goverter/example/enum/unknown/output"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source input.Color) (output.Color, error) {
	var outputColor output.Color
	switch source {
	case input.Blue:
		outputColor = output.Blue
	case input.Green:
		outputColor = output.Green
	case input.Red:
		outputColor = output.Red
	default:
		return outputColor, fmt.Errorf("unexpected enum element: %v", source)
	}
	return outputColor, nil
}

enum:unknown @ignore does nothing in the default case of the switch statement.

Example (click me)
go
package example

import (
	"github.com/jmattheis/goverter/example/enum/unknown/input"
	"github.com/jmattheis/goverter/example/enum/unknown/output"
)

// goverter:converter
// goverter:enum:unknown @ignore
type Converter interface {
	Convert(input.Color) output.Color
}
go
package input

type Color int
const (
    Green Color = iota
    Blue
    Red
)
go
package output

type Color string
const (
    Green Color = "green"
    Blue  Color = "blue"
    Red   Color = "red"
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	input "github.com/jmattheis/goverter/example/enum/unknown/input"
	output "github.com/jmattheis/goverter/example/enum/unknown/output"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source input.Color) output.Color {
	var outputColor output.Color
	switch source {
	case input.Blue:
		outputColor = output.Blue
	case input.Green:
		outputColor = output.Green
	case input.Red:
		outputColor = output.Red
	default: // ignored
	}
	return outputColor
}

enum:unknown @panic panics in the default case of the switch statement.

Example (click me)
go
package example

import (
	"github.com/jmattheis/goverter/example/enum/unknown/input"
	"github.com/jmattheis/goverter/example/enum/unknown/output"
)

// goverter:converter
// goverter:enum:unknown @panic
type Converter interface {
	Convert(input.Color) output.Color
}
go
package input

type Color int
const (
    Green Color = iota
    Blue
    Red
)
go
package output

type Color string
const (
    Green Color = "green"
    Blue  Color = "blue"
    Red   Color = "red"
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	"fmt"
	input "github.com/jmattheis/goverter/example/enum/unknown/input"
	output "github.com/jmattheis/goverter/example/enum/unknown/output"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source input.Color) output.Color {
	var outputColor output.Color
	switch source {
	case input.Blue:
		outputColor = output.Blue
	case input.Green:
		outputColor = output.Green
	case input.Red:
		outputColor = output.Red
	default:
		panic(fmt.Sprintf("unexpected enum element: %v", source))
	}
	return outputColor
}

enum:unknown KEY: use an enum key in the default case of the switch statement

Example (click me)
go
package example

import (
	"github.com/jmattheis/goverter/example/enum/unknown/key/input"
	"github.com/jmattheis/goverter/example/enum/unknown/key/output"
)

// goverter:converter
type Converter interface {
    // goverter:enum:unknown Unknown
    Convert(input.Color) output.Color
}
go
package input

type Color int

const (
    Green Color = iota
    Blue
)
go
package output

type Color string
const (
    Unknown Color = "unknown"
    Green   Color = "green"
    Blue    Color = "blue"
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	input "github.com/jmattheis/goverter/example/enum/unknown/key/input"
	output "github.com/jmattheis/goverter/example/enum/unknown/key/output"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source input.Color) output.Color {
	var outputColor output.Color
	switch source {
	case input.Blue:
		outputColor = output.Blue
	case input.Green:
		outputColor = output.Green
	default:
		outputColor = output.Unknown
	}
	return outputColor
}

enum:exclude

enum:exclude [PACKAGE:]NAME can be defined as CLI argument or converter comment.

You can exclude falsely detected enums with exclude. This is useful when a type qualifies as enum but isn't one. If PACKAGE is unset, goverter will use the package of the converter interface.

Both PACKAGE and NAME can be regular expressions.

Example (click me)
go
package example

import (
	"time"
)

// goverter:converter
// goverter:enum:unknown @panic
// goverter:enum:exclude MyDuration
// goverter:enum:exclude time:Duration
type Converter interface {
	Convert(MyDuration) time.Duration
}

type MyDuration int64

const (
	Nanoseconds  MyDuration = 1
	Microseconds MyDuration = 1000 * Nanoseconds
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	exclude "github.com/jmattheis/goverter/example/enum/exclude"
	"time"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source exclude.MyDuration) time.Duration {
	return time.Duration(source)
}

enum:map SOURCE TARGET

enum:map SOURCE TARGET can be defined as method comment.

enum:map can be used to map an enum key of the source enum type to the target type. In this example we have two spellings of Gray|Grey.

Example (click me)
go
package example

import (
	"github.com/jmattheis/goverter/example/enum/map/input"
	"github.com/jmattheis/goverter/example/enum/map/output"
)

// goverter:converter
// goverter:enum:unknown @panic
type Converter interface {
    // goverter:enum:map Gray Grey
    Convert(input.Color) output.Color
}
go
package input

type Color int

const (
    Green Color = 1
    Gray  Color = 3
)
go
package output

type Color string
const (
    Green Color = "green"
    Grey  Color = "Grey"
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	"fmt"
	input "github.com/jmattheis/goverter/example/enum/map/input"
	output "github.com/jmattheis/goverter/example/enum/map/output"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source input.Color) output.Color {
	var outputColor output.Color
	switch source {
	case input.Gray:
		outputColor = output.Grey
	case input.Green:
		outputColor = output.Green
	default:
		panic(fmt.Sprintf("unexpected enum element: %v", source))
	}
	return outputColor
}

You can also use any of the @actions from enum:unknown. E.g.

Example (click me)
go
package example

import (
	"github.com/jmattheis/goverter/example/enum/map-panic/input"
	"github.com/jmattheis/goverter/example/enum/map-panic/output"
)

// goverter:converter
// goverter:enum:unknown @panic
type Converter interface {
    // goverter:enum:map Gray @panic
    Convert(input.Color) output.Color
}
go
package input

type Color int

const (
    Green Color = 1
    Gray  Color = 3
)
go
package output

type Color string
const (
    Green Color = "green"
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	"fmt"
	input "github.com/jmattheis/goverter/example/enum/map-panic/input"
	output "github.com/jmattheis/goverter/example/enum/map-panic/output"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source input.Color) output.Color {
	var outputColor output.Color
	switch source {
	case input.Gray:
		panic(fmt.Sprintf("unexpected enum element: %v", source))
	case input.Green:
		outputColor = output.Green
	default:
		panic(fmt.Sprintf("unexpected enum element: %v", source))
	}
	return outputColor
}

enum:transform ID [CONFIG]

enum:transform ID [CONFIG] can be defined as method comment.

enum:transform allows you to transform multiple enum keys to the target keys. There is currently one builtin transformers, but you can define transformers yourself.

enum:transform regex SEARCH REPLACE

With regex you can do search and replace with regex of the enum keys.

Example (click me)
go
package example

// goverter:converter
// goverter:enum:unknown @panic
type Converter interface {
	// goverter:enum:transform regex Col(\w+) ${1}Color
	Convert(InputColor) OutputColor
	// goverter:enum:transform regex (\w+)Color Col${1}
	Convert2(OutputColor) InputColor
}

type InputColor int

const (
	ColGreen InputColor = iota
	ColBlue
	ColRed
)

type OutputColor string

const (
	GreenColor OutputColor = "green"
	BlueColor  OutputColor = "blue"
	RedColor   OutputColor = "red"
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	"fmt"
	transformregex "github.com/jmattheis/goverter/example/enum/transform-regex"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source transformregex.InputColor) transformregex.OutputColor {
	var exampleOutputColor transformregex.OutputColor
	switch source {
	case transformregex.ColBlue:
		exampleOutputColor = transformregex.BlueColor
	case transformregex.ColGreen:
		exampleOutputColor = transformregex.GreenColor
	case transformregex.ColRed:
		exampleOutputColor = transformregex.RedColor
	default:
		panic(fmt.Sprintf("unexpected enum element: %v", source))
	}
	return exampleOutputColor
}
func (c *ConverterImpl) Convert2(source transformregex.OutputColor) transformregex.InputColor {
	var exampleInputColor transformregex.InputColor
	switch source {
	case transformregex.BlueColor:
		exampleInputColor = transformregex.ColBlue
	case transformregex.GreenColor:
		exampleInputColor = transformregex.ColGreen
	case transformregex.RedColor:
		exampleInputColor = transformregex.ColRed
	default:
		panic(fmt.Sprintf("unexpected enum element: %v", source))
	}
	return exampleInputColor
}

enum:transform CUSTOM

You can define a custom transformer by adding goverter as dependency to your project and then creating a new main package in your project for your customized goverter. E.g. ./goverter/run.go. Afterwards, you have to pass your custom enum transformer to cmd.Run and then you can execute it via go run ./goverter (use the package where you created you customized goverter). Here is an example that adds a trim-prefix transformer.

Example (click me)
go
package main

import (
	"os"
	"strings"

	"github.com/jmattheis/goverter/cli"
	"github.com/jmattheis/goverter/enum"
)

func main() {
	opts := cli.RunOpts{
		EnumTransformers: map[string]enum.Transformer{
			"trim-prefix": trimPrefix,
		},
	}
	cli.Run(os.Args, opts)
}

func trimPrefix(ctx enum.TransformContext) (map[string]string, error) {
	m := map[string]string{}
	for key := range ctx.Source.Members {
		targetKey := strings.TrimPrefix(key, ctx.Config)
		if _, ok := ctx.Target.Members[targetKey]; ok {
			m[key] = targetKey
		}
	}
	return m, nil
}
go
package example

// goverter:converter
// goverter:enum:unknown @panic
type Converter interface {
	// goverter:enum:transform trim-prefix Color
	Convert(InputColor) OutputColor
}

type InputColor int

const (
	ColorGreen InputColor = iota
	ColorBlue
	ColorRed
)

type OutputColor string

const (
	Green OutputColor = "green"
	Blue  OutputColor = "blue"
	Red   OutputColor = "red"
)
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	"fmt"
	example "goverter/example"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source example.InputColor) example.OutputColor {
	var exampleOutputColor example.OutputColor
	switch source {
	case example.ColorBlue:
		exampleOutputColor = example.Blue
	case example.ColorGreen:
		exampleOutputColor = example.Green
	case example.ColorRed:
		exampleOutputColor = example.Red
	default:
		panic(fmt.Sprintf("unexpected enum element: %v", source))
	}
	return exampleOutputColor
}
Regex Implementation (click me)
go
package enum

import (
	"fmt"
	"regexp"
	"strings"
)

var DefaultTransformers = map[string]Transformer{
	"regex": transformRegex,
}

func transformRegex(ctx TransformContext) (map[string]string, error) {
	parts := strings.Split(ctx.Config, " ")
	if len(parts) != 2 {
		return nil, fmt.Errorf("invalid config, expected two strings separated by space")
	}

	pattern, err := regexp.Compile(parts[0])
	if err != nil {
		return nil, fmt.Errorf("invalid pattern %q: %w", parts[0], err)
	}

	m := map[string]string{}
	for key := range ctx.Source.Members {
		targetKey := pattern.ReplaceAllString(key, parts[1])
		if _, ok := ctx.Target.Members[targetKey]; ok {
			m[key] = targetKey
		}
	}
	return m, nil
}