CUE v0.12.0 introduced an experimental new command:
gengotypes
.
This command generates Go types from CUE definitions and places them in .go
files. It uses sensible defaults for the generated Go code that you can
override by configuring various CUE attributes.
This guide shows you how to use the cue exp gengotypes
command.
Why was gengotypes
introduced?
When a Go program works with CUE it can be useful to declare Go types which mirror its CUE schemas.
For example, if the program loads a YAML configuration file and validates it using a CUE schema it’s often useful to hold the config as a Go struct value that controls how the program should behave.
Using gengotypes
allows you to declare your schemas in CUE and automatically
derive compatible Go types – without having to repeat yourself or maintain two
versions of the same structure.
Generating Go types
Start with some CUE that contains at least one definition:
package pet
// These are the only pet types we can handle.
petTypes: ["dog", "cat", "goldfish"]
// A dog tracks information we hold about each dog.
#dog: {
// A dog has at least one name.
name!: string
age?: float & <30
}
Hidden definitions (fields with names that start _#
) are ignored by the
gengotypes
command.
Run the cue exp gengotypes
command targetting the single CUE package in the
current directory:
$ cue exp gengotypes .
The command is silent when it succeeds.
Observe the contents of the cue_types_gen.go
file:
// Code generated by "cue exp gengotypes"; DO NOT EDIT.
package pet
// A dog tracks information we hold about each dog.
type Dog struct {
// A dog has at least one name.
Name string `json:"name"`
Age float64 `json:"age,omitempty"`
}
Notice these differences between the contents of
pets.cue
and
cue_types_gen.go
:
- By default,
gengotypes
ensures the first character of each struct’s name is upper-cased (#dog
vsDog
). - The top-level regular field
petTypes
and its comment aren’t present in the Go file. Only fields inside a definition are translated to Go. - The optional field
age
has a numeric constraint in CUE (<30
) which can’t be expressed in the simpler, less powerful Go type system – so the Go encodes afloat64
type. Generated Go types are guaranteed to accept any value accepted by the CUE definitions but, as withage
, they may be more general.
Controlling the generated Go
If you need to control the generated Go package, type, and field names, you can
use the @go()
attribute to specify them in your CUE:
Add another CUE file, morePets.cue
, containing the following code:
package pet
@go(acmecorppets) // Rename this package when emitted as Go.
// A cat represents an instance of a domestic cat.
#cat: {
@go(cat) // Rename this definition when emitted as Go.
// Cats consider themselves to have a title, not a name.
title!: string @go(Name) // Rename this field when emitted as Go
socialMediaAccount!: string @go(-) // Don't emit this field as Go.
}
#horse: {
@go(-) // Don't emit this definition as Go.
status: "Unsupported"
}
Run the cue exp gengotypes
command again:
$ cue exp gengotypes .
Observe the new contents of the cue_types_gen.go
file:
// Code generated by "cue exp gengotypes"; DO NOT EDIT.
package acmecorppets
// A cat represents an instance of a domestic cat.
type cat struct {
// Cats consider themselves to have a title, not a name.
Name string `json:"title"`
}
// A dog tracks information we hold about each dog.
type Dog struct {
// A dog has at least one name.
Name string `json:"name"`
Age float64 `json:"age,omitempty"`
}
Notice these differences between the contents of
morePets.cue
and the new
cue_types_gen.go
:
- At the package level:
- The
@go(acmecorppets)
attribute renamed the generated Go package frompet
. - The
cue
command targetted the whole of the CUE package so the dog-related contents ofpets.cue
are included under the renamed Go package. Only a single package-level renaming attribute is needed.
- The
- Inside
#cat
:- The definition-level
@go(cat)
attribute renamed the generated Go type from the default that would otherwise have been emitted (Cat
). - The field-level
@go(Name)
attribute renamed the generated Go field fromTitle
. - The field-level
@go(-)
attribute caused thesocialMediaAccount
field to be omitted from the generated Go type.
- The definition-level
- Inside
#horse
, the definition-level@go(-)
attribute caused the entire definition to be omitted from the generated Go.
You can also use the @go()
attribute to control the type of a generated
field – see
cue help exp gengotypes
for more information.
gengotypes
command is still in an experimental stage, which means that it
may be changed or removed at any time. The objective is for the CUE project to
gain experience through your feedback about this
experimental command, and then move the feature elsewhere.Related content
- Reference: cue help exp gengotypes –
the built-in help text for the
cue exp gengotypes
command