genstruct

package module
v0.1.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 15, 2025 License: MIT Imports: 13 Imported by: 1

README

genstruct

Logo

A Go library for generating statically defined Go structs with support for references between structures.

Features

  • Generate Go code for static structs and arrays
  • Automatic creation of constants, variables, and slices
  • Smart naming of variables based on identifier fields
  • Reference embedding via struct tags to connect related structs
  • Customizable code generation

Installation

go get github.com/conneroisu/genstruct

Basic Usage

// Define your struct type
type Animal struct {
    ID     string
    Name   string
    Species string
    Diet   string
}

// Create a slice of structs
animals := []Animal{
    {ID: "lion-001", Name: "Leo", Species: "Lion", Diet: "Carnivore"},
    {ID: "tiger-001", Name: "Stripes", Species: "Tiger", Diet: "Carnivore"},
}

// Create a generator with functional options
generator := genstruct.NewGenerator(
    genstruct.WithPackageName("zoo"),       // Target package name
    genstruct.WithTypeName("Animal"),       // Struct type name
    genstruct.WithConstantIdent("Animal"),  // Prefix for constants
    genstruct.WithVarPrefix("Animal"),      // Prefix for variables
    genstruct.WithOutputFile("animals.go"), // Output file path
)

// Generate the code
err := generator.Generate(animals)

Struct Reference Embedding

A powerful feature of genstruct is the ability to automatically populate fields in one struct by referencing values from another struct. References can be created using either direct struct references ([]Tag) or pointer-based struct references ([]*Tag). Pointer-based references are recommended as they are more memory efficient and allow for more flexible data structures.

How it works
  1. Define your structs with reference fields
  2. Use the structgen tag to specify the source field
  3. Pass all datasets to the Generate method
Example
// Define your tag struct
type Tag struct {
    ID   string
    Name string
    Slug string
}

// Define your post struct with references to tags
type Post struct {
    ID       string
    Title    string
    TagSlugs []string  // Contains tag slugs
    Tags     []*Tag    `structgen:"TagSlugs"` // Will be populated from TagSlugs with pointers to Tag objects
}

// Create your data
tags := []Tag{
    {ID: "tag-001", Name: "Go", Slug: "go"},
    {ID: "tag-002", Name: "Programming", Slug: "programming"},
}

posts := []Post{
    {
        ID: "post-001", 
        Title: "Introduction to Go",
        TagSlugs: []string{"go", "programming"},
    },
}

// Create a generator with functional options
generator := genstruct.NewGenerator(
    genstruct.WithPackageName("blog"),
    genstruct.WithOutputFile("blog_generated.go"),
)

// Generate code with both datasets
err := generator.Generate(posts, tags)

The generated code will include:

  1. Constant definitions for all Post IDs
  2. Variable definitions for each Post
  3. A slice containing all Posts
  4. Constant definitions for all Tag IDs
  5. Variable definitions for each Tag
  6. A slice containing all Tags
  7. Cross-references between Posts and Tags (the Tags field in each Post will contain pointers to the generated Tag variables)

All of this is generated in a single file, with a single generator call.

Configuration Options

Configuration is done through functional options:

  • WithPackageName(name): Sets the package name for the generated file
  • WithTypeName(name): Sets the struct type name
  • WithConstantIdent(name): Sets the prefix for generated constants
  • WithVarPrefix(name): Sets the prefix for generated variables
  • WithOutputFile(path): Sets the output file path
  • WithIdentifierFields(fields): Sets fields to use for naming (default: "ID", "Name", "Slug", "Title", "Key", "Code")
  • WithCustomVarNameFn(func): Sets a custom function to control variable naming
  • WithLogger(logger): Sets a custom slog.Logger instance

Many of these options are automatically inferred if not specified:

  • TypeName: Inferred from the struct type in the data
  • ConstantIdent: Defaults to TypeName if not specified
  • VarPrefix: Defaults to TypeName if not specified
  • OutputFile: Defaults to lowercase(typename_generated.go)
  • IdentifierFields: Uses default fields if not specified
  • Logger: Uses the default logger if not specified

Export mode (referencing types from other packages) is automatically determined based on the output file path. If the path contains directory separators, it will use qualified imports when referencing types from other packages.

Dependencies

genstruct

import "github.com/conneroisu/genstruct"

Package genstruct provides an importable package for generating static golang struct arrays.

Index

Constants

Verbosity levels

const (
    LevelDebug = "debug"
    LevelInfo  = "info"
    LevelWarn  = "warn"
    LevelError = "error"
)

func GetLogger

func GetLogger() *slog.Logger

GetLogger returns the default logger or initializes a new one if it doesn't exist

func InitLogger

func InitLogger() *slog.Logger

InitLogger initializes the logger with command line flags

func WithLevel

func WithLevel(level slog.Level) *slog.Logger

WithLevel returns a logger with the specified level

type Config

Config holds the configuration for code generation of static structs and arrays. Many fields are optional and will be automatically inferred if not specified.

type Config struct {
    // PackageName defines the target package name
    // If not provided, defaults to "generated"
    PackageName string

    // TypeName is the name of the struct type to generate
    // If not provided, inferred from the struct type in the data
    TypeName string

    // ConstantIdent is the prefix for constants (e.g., "Post" for "PostMyPostID")
    // If not provided, defaults to the TypeName
    ConstantIdent string

    // VarPrefix is the prefix for variables (e.g., "Post" for "PostMyPost")
    // If not provided, defaults to the TypeName
    VarPrefix string

    // OutputFile is the output file name
    // If not provided, defaults to lowercase(typename_generated.go)
    OutputFile string

    // IdentifierFields are the fields to try using for naming, in priority order
    // If not provided, defaults to ["ID", "Name", "Slug", "Title", "Key", "Code"]
    IdentifierFields []string

    // CustomVarNameFn is a custom function to generate variable names (optional)
    // If provided, this takes precedence over IdentifierFields
    CustomVarNameFn func(structValue reflect.Value) string

    // Logger is the slog.Logger instance to use for logging
    // If not provided, defaults to a no-op logger
    Logger *slog.Logger
}

type EmptyError

EmptyError is returned when the data given is empty.

type EmptyError struct{}

func (EmptyError) Error
func (e EmptyError) Error() string

Error returns the error message

type Generator

Generator is responsible for generating code for static struct arrays

type Generator struct {
    Config Config
    Data   any            // The primary array of structs to generate code for
    Refs   map[string]any // Additional arrays that can be referenced
    File   *jen.File
}

func NewGenerator
func NewGenerator(config Config, data any, refs ...any) (*Generator, error)

NewGenerator creates a new generator instance with support for struct references

Parameters:

  • config: Configuration options for code generation
  • data: The primary array of structs to generate code for
  • refs: Optional additional arrays that can be referenced by the primary data

The refs parameters enable the use of struct tags with the `structgen` tag to reference data between structs. For example, a Post struct with a TagSlugs field can reference Tag structs using the tag `structgen:"TagSlugs"`.

When Generate() is called, it will: 1. Generate constants, variables, and a slice for the primary data 2. Generate constants, variables, and a slice for each referenced data set 3. Create references between the primary data and the referenced data

Reference fields can be either direct structs or pointers to structs:

  • []Tag `structgen:"TagSlugs"` - Direct struct references
  • []*Tag `structgen:"TagSlugs"` - Pointer-based struct references (recommended)

Example usage:

generator, err := genstruct.NewGenerator(config, posts, tags)
if err != nil {
    // handle error
}

Many configuration options can be omitted and will be inferred automatically:

  • TypeName: Inferred from the struct type in the data slice
  • ConstantIdent: Defaults to TypeName if not specified
  • VarPrefix: Defaults to TypeName if not specified
  • OutputFile: Defaults to lowercase(typename_generated.go) if not specified
  • IdentifierFields: Has reasonable defaults if not specified

Returns an error if:

  • The data is not a slice or array
  • The data is empty (no elements to analyze)
  • The data elements are not structs
  • Required fields couldn't be inferred

func (*Generator) Generate
func (g *Generator) Generate() error

Generate performs the code generation for both primary data and reference data

This method generates: 1. Constants for the primary data's IDs 2. Variables for each item in the primary data 3. A slice containing all primary data items 4. Constants for each reference data set's IDs 5. Variables for each item in each reference data set 6. A slice for each reference data set 7. Creates references between primary data and reference data as specified by structgen tags

All generated code is written to a single output file specified in the Config.

type InvalidTypeError

InvalidTypeError is returned when the type of the data is not a struct.

type InvalidTypeError struct {
    Kind reflect.Kind
}

func (InvalidTypeError) Error
func (e InvalidTypeError) Error() string

Error returns the error message

type NonSliceOrArrayError

NonSliceOrArrayError is returned when the data is not a slice or array.

type NonSliceOrArrayError struct {
    Kind reflect.Kind
}

func (NonSliceOrArrayError) Error
func (e NonSliceOrArrayError) Error() string

Error returns the error message

Generated by gomarkdoc

Documentation

Overview

Package genstruct provides tooling for generating static Go code from struct data.

The generator takes data in the form of struct slices and generates type-safe constants, variables, and slices for use in Go code. It supports referencing between different struct types using the structgen tag.

Basic usage:

generator := genstruct.NewGenerator(
    genstruct.WithPackageName("zoo"),
    genstruct.WithOutputFile("animals.go"),
)
err := generator.Generate(animals)

For struct references:

generator := genstruct.NewGenerator(
    genstruct.WithPackageName("blog"),
    genstruct.WithOutputFile("blog.go"),
)
err := generator.Generate(posts, tags)

Index

Constants

View Source
const (
	LevelDebug = "debug"
	LevelInfo  = "info"
	LevelWarn  = "warn"
	LevelError = "error"
)

Verbosity levels

Variables

This section is empty.

Functions

func GetLogger added in v0.0.5

func GetLogger() *slog.Logger

GetLogger returns the default logger or initializes a new one if it doesn't exist

func GetPackageNameFromPath added in v0.1.4

func GetPackageNameFromPath(filePath string) string

GetPackageNameFromPath extracts the containing folder name from a file path This can be used to determine the package name for a given Go file Example: "./out/penguin/gen.go" would return "penguin"

func InitLogger added in v0.0.5

func InitLogger() *slog.Logger

InitLogger initializes the logger with command line flags

func WithLevel added in v0.0.5

func WithLevel(level slog.Level) *slog.Logger

WithLevel returns a logger with the specified level

Types

type EmptyError

type EmptyError struct{}

EmptyError is returned when the data given is empty.

func (EmptyError) Error

func (e EmptyError) Error() string

Error returns the error message

type Generator

type Generator struct {
	// Primary configuration options
	PackageName      string
	TypeName         string
	ConstantIdent    string
	VarPrefix        string
	OutputFile       string
	IdentifierFields []string
	CustomVarNameFn  func(structValue reflect.Value) string
	Logger           *slog.Logger

	// Internal state
	Data any            // The primary array of structs to generate code for
	Refs map[string]any // Additional arrays that can be referenced
	File *jen.File
}

Generator is responsible for generating code for static struct arrays

func NewGenerator

func NewGenerator(opts ...Option) *Generator

NewGenerator creates a new generator instance with the specified options.

Example usage:

generator := genstruct.NewGenerator(
    genstruct.WithPackageName("mypackage"),
    genstruct.WithOutputFile("output_file.go"),
)

// Generate code for posts with tags references
err := generator.Generate(posts, tags)

Configuration is handled through functional options, and many values are automatically inferred if not specified:

  • TypeName: Inferred from the struct type in the data provided to Generate()
  • ConstantIdent: Defaults to TypeName if not specified
  • VarPrefix: Defaults to TypeName if not specified
  • OutputFile: Defaults to lowercase(typename_generated.go) if not specified
  • IdentifierFields: Uses default fields if not specified
  • Logger: Uses the default logger if not specified

Export mode (referencing types from other packages) is automatically determined based on the output file path. If the path contains directory separators, it will use qualified imports when referencing types from other packages.

func (*Generator) Generate

func (g *Generator) Generate(data any, refs ...any) error

Generate performs the code generation for both primary data and reference data.

Parameters:

  • data: The primary array of structs to generate code for (can be slice, array, or pointer to slice/array)
  • refs: Optional additional arrays that can be referenced by the primary data

The refs parameters enable struct references via the `structgen` tag. For example, a Post struct with a TagSlugs field can reference Tag structs:

type Post struct {
    ID       string
    TagSlugs []string  // Contains identifiers
    Tags     []*Tag    `structgen:"TagSlugs"` // Will be populated automatically
}

Reference fields can be either direct structs or pointers to structs:

  • []Tag `structgen:"TagSlugs"` - Direct struct references
  • []*Tag `structgen:"TagSlugs"` - Pointer-based struct references (recommended)

This method generates: 1. Constants for the primary data's IDs 2. Variables for each item in the primary data 3. A slice containing all primary data items 4. Constants for each reference data set's IDs 5. Variables for each item in each reference data set 6. A slice for each reference data set 7. Creates references between primary data and reference data as specified by structgen tags

All generated code is written to a single output file specified in the OutputFile field.

Returns an error if:

  • The data is not a slice, array, or pointer to slice/array
  • The data is empty (no elements to analyze)
  • The data elements are not structs
  • Required fields couldn't be inferred

type InvalidTypeError

type InvalidTypeError struct {
	Kind reflect.Kind
}

InvalidTypeError is returned when the type of the data is not a struct.

func (InvalidTypeError) Error

func (e InvalidTypeError) Error() string

Error returns the error message

type NonSliceOrArrayError

type NonSliceOrArrayError struct {
	Kind reflect.Kind
}

NonSliceOrArrayError is returned when the data is not a slice or array.

func (NonSliceOrArrayError) Error

func (e NonSliceOrArrayError) Error() string

Error returns the error message

type Option added in v0.1.4

type Option func(g *Generator)

Option is a functional option for customizing the generator.

func WithConstantIdent added in v0.1.4

func WithConstantIdent(name string) Option

WithConstantIdent sets the prefix for generated constants. For example, with prefix "Animal", constants will be named "AnimalLionID", etc. If not specified, defaults to the TypeName.

func WithCustomVarNameFn added in v0.1.4

func WithCustomVarNameFn(fn func(structValue reflect.Value) string) Option

WithCustomVarNameFn sets a custom function to control variable naming. This takes precedence over IdentifierFields if provided. The function receives a reflect.Value of the struct and should return a string to be used as the base name for the variable.

func WithIdentifierFields added in v0.1.4

func WithIdentifierFields(fields []string) Option

WithIdentifierFields sets the fields to use for variable naming. These fields are checked in order until a non-empty string field is found. If not specified, defaults to ["ID", "Name", "Slug", "Title", "Key", "Code"].

func WithLogger added in v0.1.4

func WithLogger(logger *slog.Logger) Option

WithLogger sets a custom slog.Logger instance for logging during generation. If not specified, the default logger is used.

func WithOutputFile added in v0.1.4

func WithOutputFile(path string) Option

WithOutputFile sets the output file path for the generated code. The path can include directories. Export mode is automatically determined based on this path - if it contains directory separators, qualified imports will be used for external types. If not specified, defaults to lowercase(typename_generated.go).

func WithPackageName added in v0.1.4

func WithPackageName(name string) Option

WithPackageName sets the package name for the generated code. If not specified, the package name is inferred from the output file directory.

func WithTypeName added in v0.1.4

func WithTypeName(name string) Option

WithTypeName sets the type name for the generated code. If not specified, the type name is inferred from the data struct type.

func WithVarPrefix added in v0.1.4

func WithVarPrefix(name string) Option

WithVarPrefix sets the prefix for generated variables. For example, with prefix "Animal", variables will be named "AnimalLion", etc. If not specified, defaults to the TypeName.

Directories

Path Synopsis
examples
exported-blog-network
Package main demonstrates how to export complex embedded structs.
Package main demonstrates how to export complex embedded structs.
exported-blog-posts-tags
Package main demonstrates how to export blog post data with tag references.
Package main demonstrates how to export blog post data with tag references.
exported-data-zoo
Package main shows how to export data from a package.
Package main shows how to export data from a package.
logging-circus-show
Package main shows how to use the generator with a custom logger.
Package main shows how to use the generator with a custom logger.
zoo

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL