Skip to content

toniphan21/go-composer-gen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-composer-gen

go-composer-gen is a tool for your custom generator that allows you to compose multiple small, focused operation structs into a single, cohesive service implementation. It automatically handles dependency injection and interface generation, allowing you to build complex services from decoupled units of logic.

go-composer-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-composer-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

give you have source code with these structs

// file: source.go

package main

import "context"

type Repository interface{}
type Service interface{}
type Mailer interface{}

type createUserOp struct {
	repo Repository
}

func (op *createUserOp) execute(ctx context.Context) error {
	return nil
}

type updateUserOp struct {
	mailer  Mailer
	service Service
}

func (op *updateUserOp) execute(ctx context.Context, id int) error {
	return nil
}

type deleteUserOp struct {
	repository Repository
	mailer     Mailer
}

func (op *deleteUserOp) execute(ctx context.Context, id string) error {
	return nil
}

using the configuration

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

packages {
  ["github.com/gen/project"] {
    interface_name = "Service"
    receivers {
      new { struct_name = "createUserOp" exported_as = "CreateUser" }
      new { struct_name = "updateUserOp" exported_as = "UpdateUser" }
      new { struct_name = "deleteUserOp" exported_as = "DeleteUser" }
    } 
  }
}

they will be composed to a single generated code

// golden-file: gen_composer.go
// Code generated by go-composer-gen - dev. DO NOT EDIT.

package main

import "context"

type Service interface {
	CreateUser(ctx context.Context) error

	UpdateUser(ctx context.Context, id int) error

	DeleteUser(ctx context.Context, id string) error
}

type serviceImpl struct {
	createUserOp *createUserOp
	updateUserOp *updateUserOp
	deleteUserOp *deleteUserOp
}

func (s *serviceImpl) CreateUser(ctx context.Context) error {
	return s.createUserOp.execute(ctx)
}

func (s *serviceImpl) UpdateUser(ctx context.Context, id int) error {
	return s.updateUserOp.execute(ctx, id)
}

func (s *serviceImpl) DeleteUser(ctx context.Context, id string) error {
	return s.deleteUserOp.execute(ctx, id)
}

type serviceDeps struct {
	repository Repository
	mailer     Mailer
	service    Service
}

func newService(deps *serviceDeps) Service {
	impl := &serviceImpl{
		createUserOp: &createUserOp{repo: deps.repository},
		deleteUserOp: &deleteUserOp{
			mailer:     deps.mailer,
			repository: deps.repository,
		},
		updateUserOp: &updateUserOp{
			mailer:  deps.mailer,
			service: deps.service,
		},
	}
	return impl
}

var _ Service = (*serviceImpl)(nil)

As a library

Example code

package yourgenerator

import (
	"fmt"

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

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

	generator := composergen.New(fileManager)

	pkgs, err := composergen.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-composer-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

compose multiple small, focused operation structs into a single, cohesive service implementation.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors