Piccolo
A Go code generation tool that injects method signatures from struct methods into interfaces based on comment directives.
Installation
go install github.com/akhilmhdh/piccolo@latest
Or add it as a tool in your go.mod:
tool github.com/akhilmhdh/piccolo
Usage
1. Define your struct with methods
// internal/service/user_service.go
package service
type UserService struct{}
func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
return nil, nil
}
func (s *UserService) CreateUser(ctx context.Context, req *CreateUserRequest) (*User, error) {
return nil, nil
}
func (s *UserService) DeleteUser(ctx context.Context, id string) error {
return nil
}
2. Create an interface with piccolo directives
// api/interfaces.go
package api
// piccolo: package internal/service
// piccolo: struct UserService
// piccolo: method GetUser, CreateUser, DeleteUser
type UserRepository interface {
// piccolo:start
// piccolo:end
}
3. Run piccolo
go tool piccolo gen
4. Result
// api/interfaces.go
package api
// piccolo: package internal/service
// piccolo: struct UserService
// piccolo: method GetUser, CreateUser, DeleteUser
type UserRepository interface {
// piccolo:start
GetUser(ctx context.Context, id string) (*User, error)
CreateUser(ctx context.Context, req *CreateUserRequest) (*User, error)
DeleteUser(ctx context.Context, id string) error
// piccolo:end
}
Directives
| Directive |
Description |
Example |
piccolo: package <path> |
Package path relative to module root |
piccolo: package internal/service |
piccolo: struct <names> |
Comma-separated struct names to pull methods from |
piccolo: struct UserService, OrderService |
piccolo: method <names> |
Comma-separated method names to include |
piccolo: method GetUser, CreateUser |
piccolo: import-alias <orig> <alias> |
Replace package prefix in generated types |
piccolo: import-alias types mytypes |
Markers
Use // piccolo:start and // piccolo:end markers inside the interface to define where generated methods should be placed:
type MyInterface interface {
// piccolo:start
// Generated methods go here
// piccolo:end
// Your custom methods stay here
CustomMethod() error
}
Without markers: The entire interface body is replaced with generated methods.
Features
Multi-Struct Support
Pull methods from multiple structs into a single interface:
// piccolo: package internal/service
// piccolo: struct UserService, OrderService, ProductService
// piccolo: method GetUser, GetOrder, GetProduct
type CombinedRepository interface {
// piccolo:start
// piccolo:end
}
Ambiguous Method Detection
If the same method name exists in multiple specified structs, piccolo will error:
Error: ambiguous method GetUser: found in multiple structs [UserService OrderService]
Import Alias
Handle type name collisions when the target file uses a different import alias:
// Source file uses: import "github.com/foo/types"
// Target file uses: import mytypes "github.com/foo/types"
// piccolo: package internal/service
// piccolo: struct UserService
// piccolo: import-alias types mytypes
// piccolo: method GetUser
type UserRepository interface {
// piccolo:start
// GetUser(ctx context.Context, id string) (*mytypes.User, error)
// piccolo:end
}
Idempotent
Running piccolo gen multiple times produces the same result. Safe to run in CI/CD or git hooks.
Example
See the example directory for a complete working example.
cd example
go tool piccolo gen
go build ./...
go run .
How It Works
- Scan: Recursively scans the current directory for Go files
- Parse: Finds interfaces with piccolo comment directives
- Extract: Uses
go list and go/parser to extract method signatures from specified structs
- Generate: Injects method signatures into the interface (between markers or replacing the body)
- Write: Updates the file in-place
License
MIT License - see LICENSE