/go-pinfomap

Generates Go code from a template by referencing package information such as package names, imports, and struct fields.

Primary LanguageGoApache License 2.0Apache-2.0

pinfomap

Description

Generates Go code from a template by referencing package information such as package names, imports, and struct fields.

Examples

Accessor Generation

./foo.go contains the sample struct Foo:

package examples

import (
	goimports "github.com/incu6us/goimports-reviser/v3/reviser"
	"text/template"
)

type Foo struct {
	bar  string `accessor:"setter,getter=true"`
	Baz  int
	qux  template.Template    `accessor:"getter,setter=false"`
	quux *goimports.SourceDir `accessor:"setter"`
}

./gen_foo_accessor_go/main.go serves as an accessor generator for the struct. You can place the generator comment //go:generate go run ./gen_foo_accessor_go/ in the same directory as ./foo.go:

package main

import (
	"github.com/knaka/go-pinfomap"
	"github.com/knaka/go-pinfomap/examples"
	"github.com/knaka/go-pinfomap/generator"

	"log"
)

func main() {
	// Extracts information about a struct by passing an instance of the struct.
	// Here, we're using 'examples.Foo{}' with an option to include fields tagged as "accessor".
	structInfo, err := pinfomap.NewStructInfo(examples.Foo{}, pinfomap.WithTags("accessor"))
	if err != nil {
		log.Fatalf("failed to get struct info: %v", err)
	}

	// You can also specify a struct by its name to extract information.
	// Use just the name "Foo" for structs in the current package or provide the full path
	// like "github.com/knaka/foo/bar.baz" for the other structs.
	// This approach is useful for accessing structs dynamically or when they're not directly accessible.
	_, err = pinfomap.NewStructInfo("Foo", pinfomap.WithTags("accessor"))
	if err != nil {
		log.Fatalf("failed to get struct info: %v", err)
	}

	// Adding additional data to the 'structInfo' which can be utilized in the template.
	structInfo.Data = map[string]any{
		"AdditionalComment": "This is a comment.",
	}

	// Generates Go code based on the 'AccessorTemplate' and the provided 'structInfo'.
	err = generator.GenerateGo(pinfomap.AccessorTemplate, structInfo)
	if err != nil {
		log.Fatalf("failed to generate go: %v", err)
	}
}

Running go run ./gen_foo_accessor_go/ will generate the following code as ./foo_accessor.go:

// Code generated by gen_foo_accessor_go; DO NOT EDIT.

package examples

import (
	"text/template"

	"github.com/incu6us/goimports-reviser/v3/reviser"
)

func (rcv *Foo) GetBar() string {
	return rcv.bar
}

func (rcv *Foo) SetBar(value string) {
	rcv.bar = value
}

func (rcv *Foo) GetQux() template.Template {
	return rcv.qux
}

func (rcv *Foo) SetQuux(value *reviser.SourceDir) {
	rcv.quux = value
}

Running go run ./gen_foo_accessor_go.go is also feasible if you prefer to place the generator code in the same directory as ./foo.go. Be sure to add //go:build ignore to the top of the generator's code to prevent it from being compiled and linked with other code.

While the above example is using the template AccessorTemplate, you can use your own template by passing it to pinfomap.Generate. The AccessorTemplate is defined as follows:

{{- /* gotype: github.com/knaka/go-pinfomap.Struct */ -}}

// Code generated by {{GeneratorName}}; DO NOT EDIT.

package {{.Package.Name}}

import (
	{{- range .Imports }}
		"{{.}}"
	{{- end }}
)

{{- $structName := .StructName }}

{{- range .PrivateFields }}
	{{- if .Params.getter }}
		func (rcv *{{$structName}}) Get{{.CapName}}() {{.Type}} {
			return rcv.{{.Name}}
		}
	{{- end }}

	{{- if .Params.setter }}
		func (rcv *{{$structName}}) Set{{.CapName}}(value {{.Type}}) {
			rcv.{{.Name}} = value
		}
	{{- end }}
{{- end }}

The resulting Go code is automatically formatted with goimports-reviser, allowing you to write the template without worrying about the strictness of import statements or unnecessary empty lines.