This guide demonstrates how to generate CUE from types defined in a local Go main package, placing the CUE in the same directory as the Go code.

Initialize Go and CUE modules

1

Create a Go module, or use an existing one if that’s more suitable for your situation:

TERMINAL
$ go mod init an.example
...
2

Create a CUE module if you don’t already have one:

TERMINAL
$ cue mod init an.example

This module will hold the CUE generated from your local Go types.

Fetch or create your Go types

3

Place Go code in the current working directory that contains the types you’re interested in. If you are following this guide by working inside an existing Go package then the code and types will already be in place.

This guide uses the following example: a simple program that loads a JSON-encoded config from its stdin.

You don’t need to use this example in any way. You should use your own Go code and types.

main.go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
)

type Config struct {
	Vals  []Val `json:"vals"`
	Level int   `json:"level"`
}

type Val struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

func main() {
	var cfg Config
	dec := json.NewDecoder(os.Stdin)
	if err := dec.Decode(&cfg); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Config level: %d.\n", cfg.Level)
	fmt.Printf("Val count: %d.\n", len(cfg.Vals))
	if len(cfg.Vals) > 0 {
		fmt.Printf("First val name: %q.\n", cfg.Vals[0].Name)
	}
}

config.json contains a sample configuration to test our example program:

config.json
{
    "level": 42,
    "vals": [
        {
            "name": "cueckoo",
            "value": "bird"
        },
        {
            "name": "porcuepine",
            "value": "mammal"
        }
    ]
}

We check that our example code accepts the sample configuration:

TERMINAL
$ cat config.json | go run .
Config level: 42.
Val count: 2.
First val name: "cueckoo".

Generate CUE from Go types

4

Use the cue command to generate CUE from the Go types in the main package:

TERMINAL
$ cue get go --local .

The main package is inferred from the Go files present in our example and the symbol ., which refers to the Go package in the current working directory. The --local flag is required because of issue #452, and when that issue is resolved the flag won’t be needed (so long as the CUE and Go package import paths are identical).

5

Inspect the generated CUE code:

main_go_gen.cue
// Code generated by cue get go. DO NOT EDIT.

//cue:generate cue get go an.example

package main

#Config: {
	vals: [...#Val] @go(Vals,[]Val)
	level: int @go(Level)
}

#Val: {
	name:  string @go(Name)
	value: string @go(Value)
}

Test the generated CUE

6

We can use cue vet to validate our sample config file against the generated CUE:

TERMINAL
$ cue vet -d '#Config' . config.json

Your Go code will probably have known-good and known-bad data for testing your generated CUE.