noun - the horizontal threads in weaving, creating the fabric's structure.
weft
A Go template engine for code generation with extensible post-processing, state management, debugging, and testing utilities.
Packages
- config - Generic YAML configuration loading with validation support
- engine - Core template processing with caching and concurrent rendering
- postprocess - Extensible post-processing framework for transforming generated content
- processors - Built-in post-processors (Go imports, whitespace cleanup, headers, etc.)
- render - Template discovery, blocks, includes, and function registry
- write - File writing with coordination, locking, and composite operations
- state - File tracking, manifest management, and cleanup operations
- debug - Debugging, error handling, and template validation
- testing - Testing utilities, benchmarks, mocks, and snapshots
Basic Usage
package main
import (
"github.com/cpcf/weft/engine"
"github.com/cpcf/weft/processors"
)
func main() {
// Create template engine
eng := engine.New(
engine.WithOutputRoot("./generated"),
engine.WithFailureMode(engine.FailFast),
)
// Add post-processors for generated content
eng.AddPostProcessor(processors.NewGoImports()) // Fix Go imports & formatting
eng.AddPostProcessor(processors.NewTrimWhitespace()) // Clean whitespace
eng.AddPostProcessor(processors.NewAddGeneratedHeader("myapp", ".go")) // Add headers
// Create context
ctx := engine.NewContext(templateFS, "./generated", "mypackage")
// Render templates with post-processing
if err := eng.RenderDir(ctx, "templates", data); err != nil {
log.Fatal(err)
}
}
Custom Template Functions
weft supports custom template functions alongside its built-in functions:
import (
"text/template"
"time"
"github.com/cpcf/weft/engine"
)
// Define custom functions
customFuncs := template.FuncMap{
"formatDate": func(t time.Time) string {
return t.Format("2006-01-02")
},
"calculateTax": func(amount float64, rate float64) float64 {
return amount * rate
},
}
// Create engine with custom functions
eng := engine.New(
engine.WithCustomFunctions(customFuncs),
engine.WithOutputRoot("./generated"),
)
// Use in templates:
// {{formatDate .CreatedAt}}
// {{calculateTax .Amount 0.08}}
Post-Processing System
weft includes an extensible post-processing framework that transforms generated content:
Built-in Processors
- Go Imports - Automatically fixes imports and formats Go code using
goimports
- Trim Whitespace - Removes trailing whitespace from all lines
- Generated Headers - Adds "Code generated" headers to files
- Regex Replace - Custom regex-based transformations
Custom Processors
Create custom processors by implementing the postprocess.Processor
interface:
type MyProcessor struct{}
func (p *MyProcessor) ProcessContent(filePath string, content []byte) ([]byte, error) {
if strings.HasSuffix(filePath, ".go") {
// Custom Go transformations
return transformGoCode(content), nil
}
return content, nil
}
// Add to engine
eng.AddPostProcessor(&MyProcessor{})
Function-based Processors
For simple transformations, use function processors:
eng.AddPostProcessorFunc(func(filePath string, content []byte) ([]byte, error) {
// Convert line endings to Unix style
return bytes.ReplaceAll(content, []byte("\r\n"), []byte("\n")), nil
})
See postprocess/README.md for comprehensive documentation.
Configuration Loading
The config package provides utilities for loading YAML configuration files into your custom types:
import "github.com/cpcf/weft/config"
type MyConfig struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
Options map[string]string `yaml:"options"`
}
func main() {
var cfg MyConfig
// Load configuration from YAML file
err := config.LoadYAML("config.yaml", &cfg)
if err != nil {
log.Fatal(err)
}
// Use configuration with template engine
eng := engine.New(engine.WithOutputRoot(cfg.Options["output_dir"]))
// ...
}
See config/README.md for detailed documentation including validation and testing utilities.
Examples