postprocess

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 2, 2025 License: MIT Imports: 1 Imported by: 0

README

Post-Processing System

The post-processing system provides a generic framework for transforming generated content after template rendering but before writing to disk.

Overview

Post-processors allow you to:

  • Format and organize code (imports, whitespace)
  • Add generated file headers
  • Apply custom transformations
  • Validate generated content
  • Perform file-type specific optimizations

Basic Usage

import (
    "github.com/cpcf/weft/engine"
    "github.com/cpcf/weft/processors"
)

// Create engine and add processors
eng := engine.New()

// Add built-in processors
eng.AddPostProcessor(processors.NewGoImports())                // Fix Go imports
eng.AddPostProcessor(processors.NewTrimWhitespace())           // Clean whitespace  
eng.AddPostProcessor(processors.NewAddGeneratedHeader("myapp", ".go", ".js")) // Add headers

// Generate files
err := eng.RenderDir(ctx, "templates", data)

Built-in Processors

Go Imports (processors.NewGoImports())

Fixes import statements and formats Go code using goimports:

processor := processors.NewGoImports()
// Customize options
processor.TabWidth = 4
processor.TabIndent = false
processor.AllErrors = true
Trim Whitespace (processors.NewTrimWhitespace())

Removes trailing whitespace from all lines:

eng.AddPostProcessor(processors.NewTrimWhitespace())
Add Generated Header (processors.NewAddGeneratedHeader())

Adds "Code generated" headers to files:

// Add header to specific file types
eng.AddPostProcessor(processors.NewAddGeneratedHeader("myapp", ".go", ".java"))

// Add header to all files
eng.AddPostProcessor(processors.NewAddGeneratedHeader("myapp"))
Regex Replace (processors.NewRegexReplace())

Apply regex transformations:

// Replace TODO comments with DONE
processor, err := processors.NewRegexReplace(`TODO: (.+)`, "DONE: $1")
if err != nil {
    log.Fatal(err)
}
eng.AddPostProcessor(processor)

// Limit to specific file types
processor.WithFilePattern(`\.go$`)

Custom Processors

Implement the postprocess.Processor interface:

type CustomProcessor struct{}

func (p *CustomProcessor) ProcessContent(filePath string, content []byte) ([]byte, error) {
    // Apply custom transformation
    if strings.HasSuffix(filePath, ".go") {
        // Add custom Go code transformations
        transformed := doCustomTransform(content)
        return transformed, nil
    }
    return content, nil // Leave other files unchanged
}

// Add to engine
eng.AddPostProcessor(&CustomProcessor{})

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
})

Advanced Usage

Chaining Multiple Processors

Processors run in the order they're added:

eng.AddPostProcessor(processors.NewGoImports())           // 1. Fix imports first
eng.AddPostProcessor(processors.NewTrimWhitespace())      // 2. Clean whitespace
eng.AddPostProcessor(processors.NewAddGeneratedHeader("myapp", ".go")) // 3. Add header last
Error Handling

Processors that fail log a warning but don't stop generation:

// This processor might fail but won't break the build
eng.AddPostProcessor(processors.NewGoImports())
File-type Specific Processing
// Only process Go files
eng.AddPostProcessorFunc(func(filePath string, content []byte) ([]byte, error) {
    if !strings.HasSuffix(filePath, ".go") {
        return content, nil
    }
    // Go-specific processing here
    return processGoFile(content), nil
})

Examples in Other Languages

Java Processor
type JavaFormatter struct{}

func (j *JavaFormatter) ProcessContent(filePath string, content []byte) ([]byte, error) {
    if !strings.HasSuffix(filePath, ".java") {
        return content, nil
    }
    // Format Java code using google-java-format or similar
    return formatJavaCode(content), nil
}
Python Processor
type PythonFormatter struct{}

func (p *PythonFormatter) ProcessContent(filePath string, content []byte) ([]byte, error) {
    if !strings.HasSuffix(filePath, ".py") {
        return content, nil
    }
    // Format Python code using black or autopep8
    return formatPythonCode(content), nil
}

Best Practices

  1. Order Matters: Add processors in logical order (format → clean → annotate)
  2. File Type Checking: Always check file extensions before processing
  3. Error Handling: Return original content on errors rather than failing
  4. Performance: Keep processors lightweight for large codebases
  5. Idempotency: Ensure processors can run multiple times safely

Integration with CI/CD

Post-processors integrate seamlessly with build pipelines:

// In your generator
func main() {
    eng := engine.New()
    
    // Add standard processors
    eng.AddPostProcessor(processors.NewGoImports())
    eng.AddPostProcessor(processors.NewTrimWhitespace())
    eng.AddPostProcessor(processors.NewAddGeneratedHeader(os.Args[0]))
    
    // Add custom validation
    eng.AddPostProcessorFunc(validateGeneratedFiles)
    
    if err := eng.RenderDir(ctx, "templates", data); err != nil {
        log.Fatal(err)
    }
}

This ensures generated code is properly formatted, validated, and ready for version control.

Documentation

Overview

Package postprocess provides a generic framework for post-processing generated content.

The post-processing system allows you to apply transformations to generated files after template rendering but before writing to disk. This is useful for:

  • Code formatting and import organization
  • Static analysis and linting
  • Content validation and transformation
  • File-type specific optimizations

Example usage:

import (
	"github.com/cpcf/weft/engine"
	"github.com/cpcf/weft/processors"
)

eng := engine.New()
eng.AddPostProcessor(processors.NewGoImports())
eng.AddPostProcessor(myCustomProcessor)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Chain

type Chain struct {
	// contains filtered or unexported fields
}

Chain manages and executes multiple post-processors in sequence. Processors are applied in the order they were added.

func NewChain

func NewChain() *Chain

NewChain creates a new empty processor chain.

func (*Chain) Add

func (c *Chain) Add(processor Processor)

Add adds a processor to the end of the chain.

func (*Chain) AddFunc

func (c *Chain) AddFunc(fn func(filePath string, content []byte) ([]byte, error))

AddFunc adds a function as a processor to the end of the chain.

func (*Chain) Clear

func (c *Chain) Clear()

Clear removes all processors from the chain.

func (*Chain) HasProcessors

func (c *Chain) HasProcessors() bool

HasProcessors returns true if the chain contains any processors.

func (*Chain) Len

func (c *Chain) Len() int

Len returns the number of processors in the chain.

func (*Chain) Process

func (c *Chain) Process(filePath string, content []byte) ([]byte, error)

Process runs all processors in sequence on the given content. If any processor fails, processing stops and the error is returned.

type Processor

type Processor interface {
	// ProcessContent processes the content of a file and returns the transformed content.
	// The filePath parameter provides context about the file being processed.
	// Processors should return the original content unchanged if they don't apply to the file type.
	ProcessContent(filePath string, content []byte) ([]byte, error)
}

Processor defines the interface for content post-processors. Implementations should be stateless and safe for concurrent use.

type ProcessorFunc

type ProcessorFunc func(filePath string, content []byte) ([]byte, error)

ProcessorFunc is a function adapter that implements the Processor interface. It allows using regular functions as processors.

func (ProcessorFunc) ProcessContent

func (f ProcessorFunc) ProcessContent(filePath string, content []byte) ([]byte, error)

ProcessContent implements the Processor interface.

Jump to

Keyboard shortcuts

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