Skip to content

toniphan21/go-chainer-gen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-chainer-gen

go-chainer-gen transforms independent methods into structured execution chains. By using semantic analysis of your function signatures, it automates variable handoffs, error propagation, and context management - turning discrete logic units into a clean, idiomatic execute function.

Key Capabilities

  • Smart Variable Handoff: Automatically maps return values from one step to the input parameters of subsequent steps.
  • Zero-Value Returns: Automatically resolves and returns the correct zero-values for complex types during error propagation.
  • Pkl-Powered: Uses pkl-lang for type-safe, programmable configuration of your generation rules.

go-chainer-gen can be used as a standalone CLI tool or integrated into your own custom generator as a library. This is a component of my code generation toolbox.

Requirements

When running as a standalone generator, go-chainer-gen requires the pkl binary to be available on your PATH. It is used at runtime to evaluate .pkl configuration files. You can install it via:

# macOS
brew install pkl

For other platforms, see pkl-lang installation docs.

Usage

As a standalone generator

First let's set up a golang module

module github.com/gen/project

go 1.24

using the minimum configuration

// file: chainer.pkl
amends "package://nhatp.com/go/chainer-gen/pkl@0.3.0#/Config.pkl"
import "package://nhatp.com/go/chainer-gen/pkl@0.3.0#/match.pkl"

packages {
  ["github.com/gen/project"] {
    struct_name = match.with("createUserOp")
  }
}

source code

// file: main.go

package main

import "context"

type CreateUserInput struct{}

type createUserOp struct {
}

func (op *createUserOp) validate(ctx context.Context, input CreateUserInput) error {
	return nil
}

func (op *createUserOp) authorize(ctx context.Context, input CreateUserInput) error {
	return nil
}

func (op *createUserOp) handle(ctx context.Context, input CreateUserInput) error {
	return nil
}

run command in your terminal

go run nhatp.com/go/chainer-gen/cmd/go-chainer-gen generate

expected generated code

// golden-file: gen_chainer.go
// Code generated by go-chainer-gen - dev. DO NOT EDIT.

package main

import (
	"context"
	"fmt"
)

// execute runs createUserOp.validate, createUserOp.authorize, and
// createUserOp.handle in sequence.
func (op *createUserOp) execute(ctx context.Context, input CreateUserInput) error {
	v0 := op.validate(ctx, input)
	if v0 != nil {
		return fmt.Errorf("validate: %w", v0)
	}

	v1 := op.authorize(ctx, input)
	if v1 != nil {
		return fmt.Errorf("authorize: %w", v1)
	}

	v2 := op.handle(ctx, input)
	if v2 != nil {
		return fmt.Errorf("handle: %w", v2)
	}

	return nil
}

As a library

Example code

package yourgenerator

import (
	"fmt"

	"nhatp.com/go/chainer-gen"
)

func UseAsLibrary(sourceDir string) {
	// fileManager instance can be shared between commands in the toolbox
	fileManager := chainergen.NewFileManager(sourceDir, chainergen.WithBinaryName("your-generator"))
	
	var configs []chainergen.Config // build your configs here ...

	generator := chainergen.New(fileManager)

	pkgs, err := chainergen.LoadPackages(sourceDir)
	if err != nil {
		panic(err)
	}

	for _, pkg := range pkgs {
		if err := generator.Generate(pkg, configs); err != nil {
			panic(err)
		}
	}

	fmt.Println(fileManager.Files())
}

Features

Explore the features directory to see how go-chainer-gen handles various real-world scenarios:

Contributing & License

PRs are welcome! See the CONTRIBUTING. Distributed under the Apache License 2.0.

If you like the project, feel free to buy me a coffee. Thank you!

About

chain independent methods into a single function with automate variable handoffs and error propagation.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors