echotemplates

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 9, 2025 License: MIT Imports: 16 Imported by: 1

README

Echo Templates

Echo Templates extends the echo library with templating capabilities for LLM prompt construction.

Installation

go get github.com/mkozhukh/echo-templates

Features

  • 🚀 Simple string templates - Generate messages directly from strings
  • 📁 File-based templates - Organize templates in filesystem
  • 📦 Embedded templates - Bundle templates in your binary
  • 🔄 Hot reload - Automatic template reloading in development
  • 🎯 Smart imports - Compose templates with dynamic imports
  • ⚙️ Extensible - Custom template sources and import resolution

Quick Start

Simple String Template

For quick and simple use cases, generate messages directly from strings:

package main

import (
    "fmt"
    "github.com/mkozhukh/echo-templates"
)

func main() {
    // Generate messages from a string template
    messages, err := echotemplates.Generate(
        "Hello {{name}}! How can I help you with {{topic}} today?",
        map[string]any{
            "name": "Alice",
            "topic": "Go programming",
        },
    )
    if err != nil {
        panic(err)
    }
    
    fmt.Println(messages[0].Content)
    // Output: Hello Alice! How can I help you with Go programming today?
}
File-based Templates
package main

import (
    "context"
    "fmt"
    "github.com/mkozhukh/echo"
    "github.com/mkozhukh/echo-templates"
)

func main() {
    // Create a filesystem source
    source, err := echotemplates.NewFileSystemSource("./prompts")
    if err != nil {
        panic(err)
    }
    
    // Create a template engine
    engine, err := echotemplates.New(echotemplates.Config{
        Source: source,
        DevMode: false, // Enable for development (file watching, no caching)
    })
    if err != nil {
        panic(err)
    }
    
    // Generate messages from a template
    messages, err := engine.Generate("chat/assistant", map[string]any{
        "role": "helpful",
        "domain": "mathematics",
        "user_query": "What is calculus?",
    })
    if err != nil {
        panic(err)
    }
    
    // Use with echo client
    client, _ := echo.NewClient("openai/gpt-4", "api-key")
    resp, _ := client.Call(context.Background(), messages)
    fmt.Println(resp.Text)
}

Template Format

Templates use the same format as echo's TemplateMessage with additional features:

Basic Structure
@system:
You are a {{role}} assistant specializing in {{domain}}.

@user:
{{user_query}}

@assistant:
I'll help you with {{domain}}. Let me analyze your request.
Front-matter (Optional)

Templates can include metadata using YAML-like syntax at the beginning of the file:

---
temperature: 0.7
max_tokens: 1000
model: gpt-4
description: A helpful assistant template
default.role: helpful
default.style: professional
---
@system:
You are a {{role}} assistant with a {{style}} communication style.

Front-matter must be delimited by --- lines and appear at the very beginning of the file. It supports any key-value pairs:

  • Keys can be any string
  • Values can be strings or numbers (integers or floats)
  • Keys starting with default. define default values for variables
  • Common fields include temperature, max_tokens, model, description

Template Syntax

Placeholders
  1. Simple substitution: {{variable_name}}

    Hello {{name}}, welcome to {{place}}!
    
  2. With default values: {{variable_name|default_value}}

    You are a {{role|helpful}} assistant.
    
  3. Raw content (no escaping): {{{raw_content}}}

    Code: {{{code_snippet}}}
    
Imports

Include content from other templates:

  1. Simple import: {{@file_path}}

    {{@common/header}}
    
    @user:
    {{user_query}}
    
  2. Dynamic import: {{@folder/{{variable}}/file}}

    {{@styles/{{style_type}}/intro}}
    {{@personas/{{persona}}}}
    
Processing Order
  1. Import Resolution - All {{@...}} imports are processed recursively
  2. Variable Substitution - All {{variable}} placeholders are replaced
  3. Message Parsing - Content is split into messages using @role: markers

Configuration

Template Sources

Echo Templates supports multiple template sources through the TemplateSource interface:

Filesystem Source
// Create a filesystem source
source, err := echotemplates.NewFileSystemSource("./prompts")

engine, err := echotemplates.New(echotemplates.Config{
    Source: source,
    DevMode: true,  // Enable file watching and disable caching
})
Embedded Templates
//go:embed prompts/*
var embeddedTemplates embed.FS

// Create an embedded source
source := echotemplates.NewEmbedSource(embeddedTemplates, "prompts")

engine, err := echotemplates.New(echotemplates.Config{
    Source: source,
    DevMode: false, // Production mode with caching
})
Mock Source (for testing)
// Create a mock source with in-memory templates
templates := map[string]string{
    "greeting.md": "@system:\nYou are a {{role}} assistant.\n\n@user:\n{{message}}",
    "chat.md": "Hello {{name}}!",
}

source := echotemplates.NewMockSource(templates)

engine, err := echotemplates.New(echotemplates.Config{
    Source: source,
    DevMode: false,
})
Engine Configuration
engine, err := echotemplates.New(echotemplates.Config{
    // Template source (required)
    Source: source,
    
    // Development mode (default: false)
    // - true: disables caching, enables file watching
    // - false: enables caching for production
    DevMode: false,
    
    // Maximum number of templates to cache (default: 100)
    CacheSize: 100,
    
    // Default options for all Generate calls
    DefaultOptions: echotemplates.GenerateOptions{
        StrictMode: true,
        AllowMissingVars: false,
    },
})
Generation Options

Options are optional and can be passed as the last parameter:

// Without options (uses default options)
messages, err := engine.Generate("template", vars)

// With custom options
messages, err := engine.Generate("template", vars, 
    echotemplates.GenerateOptions{
        // Allow missing variables (default: false)
        AllowMissingVars: true,
        
        // Enable strict parsing (default: false)
        StrictMode: true,
        
        // Bypass cache for this generation (default: false)
        DisableCache: true,
    },
)

API Reference

Package-level Functions

These functions provide a simple way to generate messages from string templates without creating an engine:

Generate
func Generate(content string, vars map[string]any, opts ...GenerateOptions) ([]echo.Message, error)

Generates messages from a string template.

Parameters:

  • content - The template string with placeholders
  • vars - Variables to substitute in the template (supports string, int, float64, []string)
  • opts - Optional generation options

Examples:

// Simple template (creates user message)
messages, err := echotemplates.Generate(
    "Hello {{name}}, welcome to {{place}}!",
    map[string]any{"name": "Alice", "place": "Wonderland"},
)
// messages[0].Role == "user"
// messages[0].Content == "Hello Alice, welcome to Wonderland!"

// Template with different value types
messages, err = echotemplates.Generate(
    "User {{name}} (age {{age}}) scored {{score}} with tags: {{tags}}",
    map[string]any{
        "name": "Bob",
        "age": 25,                // int
        "score": 98.5,             // float64
        "tags": []string{"go", "testing"},  // []string -> "go,testing"
    },
)

// Template with role markers
messages, err = echotemplates.Generate(
    "@system:\nYou are a {{role}} assistant.\n\n@user:\n{{query}}",
    map[string]any{"role": "helpful", "query": "What is Go?"},
)
// messages[0].Role == "system"
// messages[1].Role == "user"
GenerateWithMetadata
func GenerateWithMetadata(content string, vars map[string]any, opts ...GenerateOptions) ([]echo.Message, map[string]any, error)

Generates messages from a string template and returns any metadata defined in front-matter.

Example:

template := `---
temperature: 0.7
model: gpt-4
---
Hello {{name}}!`

messages, metadata, err := echotemplates.GenerateWithMetadata(
    template,
    map[string]any{"name": "Bob"},
)
// metadata["temperature"] == 0.7
// metadata["model"] == "gpt-4"

Notes:

  • String templates do not support imports ({{@...}}). Use file-based or embedded sources for templates with imports.
  • If no role markers (@role:) are present, the content becomes a single user message.
CallOptions
func CallOptions(metadata map[string]any) []echo.CallOption

Creates echo.CallOption slice from template metadata for configuring LLM API calls.

Example:

messages, metadata, _ := engine.GenerateWithMetadata("template", vars)
opts := echotemplates.CallOptions(metadata)
client.Call(ctx, messages, opts...)

The CallOptions function automatically extracts and converts:

  • model (string) → echo.WithModel(model)
  • temperature (float64) → echo.WithTemperature(temp)
  • max_tokens (int) → echo.WithMaxTokens(maxTokens)
Engine Functions

For file-based templates, create an engine with a template source:

// Create source
source, err := echotemplates.NewFileSystemSource("./templates")

// Create engine
engine, err := echotemplates.New(echotemplates.Config{
    Source: source,
    DevMode: false,
})

// Generate from file
messages, err := engine.Generate("prompt", vars)

Advanced Usage

Using Template Metadata
// Get template with metadata
messages, metadata, err := engine.GenerateWithMetadata("ai/creative", vars)

// Access metadata fields
if temp, ok := metadata["temperature"].(float64); ok {
    // Use temperature value
}

if maxTokens, ok := metadata["max_tokens"].(int); ok {
    // Use max_tokens value
}

// Access defaults
if defaults, ok := metadata["defaults"].(map[string]any); ok {
    // Use default values
}
Custom Template Sources

Implement the TemplateSource interface to create custom sources:

type TemplateSource interface {
    Open(path string) (io.ReadCloser, error)
    Stat(path string) (TemplateInfo, error)
    List() ([]string, error)
    Watch() (<-chan string, error)
    StopWatch() error
    ResolveImport(importPath, currentPath string) string
}

Example: Database-backed templates, remote templates, etc.

Custom Import Resolution

Override import resolution for relative imports or custom logic:

type customSource struct {
    *echotemplates.FileSystemSource
}

func (s *customSource) ResolveImport(importPath, currentPath string) string {
    // Custom logic: resolve imports relative to current template
    if !filepath.IsAbs(importPath) {
        dir := filepath.Dir(currentPath)
        return filepath.Join(dir, importPath)
    }
    return "" // Use default resolution
}
File Watching in Development

In dev mode, the filesystem source automatically watches for template changes:

engine, err := echotemplates.New(echotemplates.Config{
    Source: source,
    DevMode: true, // Enables file watching
})

// Templates are automatically reloaded when files change
// No need to restart the application during development
Dynamic Imports

Create flexible templates with variable-based imports:

{{@personas/{{persona_type}}}}
{{@styles/{{writing_style}}}}

@system:
You are configured with the above persona and style.

@user:
{{user_input}}
Template Introspection
// Check if a template exists
exists := engine.TemplateExists("chat/assistant")

// List all available templates
templates, err := engine.ListTemplates()

// Get all variables used in a template
vars, err := engine.GetTemplateVariables("chat/assistant")

// Validate a template without generating
err := engine.ValidateTemplate("chat/assistant")
Clearing Cache

During development or when templates change:

engine.ClearCache()

Error Handling

The library provides specific error types for better error handling:

messages, err := engine.Generate("template", vars)
if err != nil {
    switch e := err.(type) {
    case *echotemplates.TemplateNotFoundError:
        // Handle missing template
        fmt.Printf("Template not found: %s\n", e.Name)
    case *echotemplates.VariableError:
        // Handle missing variable
        fmt.Printf("Missing variable: %s\n", e.Variable)
    case *echotemplates.ImportError:
        // Handle import failure
        fmt.Printf("Import failed: %s\n", e.ImportPath)
    case *echotemplates.ParseError:
        // Handle parse error
        fmt.Printf("Parse error at line %d: %s\n", e.Line, e.Message)
    }
}

Caching

The template engine implements an LRU cache with automatic invalidation:

  • Templates are cached after parsing (before variable substitution)
  • Cache is automatically disabled in dev mode
  • In production mode with filesystem source, cache is invalidated when template files are modified
  • Cache size is configurable
  • Can be disabled globally or per-request

Thread Safety

The template engine is thread-safe and can be used concurrently from multiple goroutines.

Why Echo Templates?

Echo Templates is about doing one thing well: managing LLM prompts.

Designed for LLM Prompts

Unlike Go's text/template or other template engines, Echo Templates understands the structure of LLM conversations:

  • Role-based messages - Native support for @system:, @user:, @assistant: markers
  • Message arrays - Outputs []echo.Message ready for LLM APIs, not just strings
  • Front-matter metadata - Embed temperature, model preferences, and other LLM parameters directly in templates
  • Minimal syntax - Just {{variables}} and {{@imports}}, no loops or conditionals
  • File watching - Templates reload automatically during prompt iteration
What It's NOT

Echo Templates intentionally doesn't include:

  • ❌ Logic operations (if/else, loops, comparisons)
  • ❌ Function calls or pipelines
  • ❌ Complex data structures
  • ❌ HTML/JS escaping
  • ❌ General-purpose templating features

If you need these features, use Go's text/template. Echo Templates focuses on making LLM prompt management simple, maintainable, and purpose-built for AI applications.

Example: Why It Matters
// With text/template (general purpose)
tmpl := template.Must(template.New("prompt").Parse(`
{{if .IsCreative}}You are a creative assistant.{{else}}You are a helpful assistant.{{end}}

User: {{.Query}}`))

var buf bytes.Buffer
tmpl.Execute(&buf, data)
// Now you need to parse this into messages somehow...

// With Echo Templates (purpose-built)
messages, _ := echotemplates.Generate(`
	@system: You are a {{role}} assistant.
	@user:
	{{query}}`,
    map[string]any{"role": roleType, "query": userQuery},
)
// Ready to send to OpenAI/Claude/etc!

License

MIT License

Copyright (c) 2025 Maksim Kozhukh

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Documentation

Overview

Example (CustomImportResolver)
package main

import (
	"log"

	echotemplates "github.com/mkozhukh/echo-templates"
)

func main() {
	// Create a custom source with import resolution
	type customSource struct {
		echotemplates.TemplateSource
		baseDir string
	}

	// Implement custom import resolution
	type customFileSource struct {
		*echotemplates.FileSystemSource
	}

	baseSource, _ := echotemplates.NewFileSystemSource("./templates")

	// Wrap the source to override import resolution
	source := &struct {
		echotemplates.TemplateSource
	}{
		TemplateSource: baseSource,
	}

	// Note: In a real implementation, you would create a proper type
	// that embeds FileSystemSource and overrides the ResolveImport method

	engine, err := echotemplates.New(echotemplates.Config{
		Source: source,
	})
	if err != nil {
		log.Fatal(err)
	}

	// Use the engine...
	_ = engine
}
Example (FileWatching)
package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	echotemplates "github.com/mkozhukh/echo-templates"
)

func main() {
	// Create a temporary directory for testing
	tmpDir, err := os.MkdirTemp("", "templates")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(tmpDir)

	// Create a filesystem source
	source, err := echotemplates.NewFileSystemSource(tmpDir)
	if err != nil {
		log.Fatal(err)
	}

	// Create engine with dev mode (enables file watching)
	engine, err := echotemplates.New(echotemplates.Config{
		Source:  source,
		DevMode: true,
	})
	if err != nil {
		log.Fatal(err)
	}

	// Create a template file
	templatePath := filepath.Join(tmpDir, "test.md")
	err = os.WriteFile(templatePath, []byte("Hello {{name}}!"), 0644)
	if err != nil {
		log.Fatal(err)
	}

	// Generate with initial content
	messages, _ := engine.Generate("test", map[string]any{"name": "World"})
	fmt.Printf("Initial: %s\n", messages[0].Content)

	// Modify the template file
	err = os.WriteFile(templatePath, []byte("Hi {{name}}!"), 0644)
	if err != nil {
		log.Fatal(err)
	}

	// Wait a moment for file watcher to detect change
	// (In real usage, this happens automatically)

	// Generate again - will use updated content
	messages, _ = engine.Generate("test", map[string]any{"name": "World"})
	fmt.Printf("Updated: %s\n", messages[0].Content)
}
Example (StringGeneration)
package main

import (
	"fmt"

	echotemplates "github.com/mkozhukh/echo-templates"
)

func main() {
	// Generate messages directly from a string template
	messages, _ := echotemplates.Generate("Hello {{name}}!", map[string]any{"name": "World"})
	fmt.Printf("Content: %s\n", messages[0].Content)
}
Output:
Content: Hello World!

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CallOptions added in v0.2.0

func CallOptions(metadata map[string]any) []echo.CallOption

CallOptions creates echo.CallOption slice from template metadata

func Extend added in v0.2.0

func Extend(metadata map[string]any, content string) map[string]any

func Generate

func Generate(content string, vars map[string]any, opts ...GenerateOptions) ([]echo.Message, error)

Generate creates messages from a string template

func GenerateWithMetadata

func GenerateWithMetadata(content string, vars map[string]any, opts ...GenerateOptions) ([]echo.Message, map[string]any, error)

GenerateWithMetadata creates messages from a string template and returns metadata

Types

type Config

type Config struct {
	// Source is the template source (required)
	Source TemplateSource

	// DevMode disables caching for development (default: false)
	DevMode bool

	// DefaultOptions applies to all Generate calls unless overridden
	DefaultOptions GenerateOptions

	// CacheSize maximum number of templates to cache in production mode (default: 100)
	CacheSize int
}

Config configures the template engine

type EmbedSource

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

EmbedSource implements TemplateSource for embedded templates

Example
package main

import (
	"embed"
	"fmt"
	"log"

	echotemplates "github.com/mkozhukh/echo-templates"
)

func main() {
	// Example with embedded templates
	// Assume you have:
	// //go:embed prompts/*
	// var embeddedTemplates embed.FS

	// For this example, we'll create a dummy embed.FS
	var embeddedTemplates embed.FS

	// Create an embedded source
	source := echotemplates.NewEmbedSource(embeddedTemplates, "prompts")

	// Create engine in production mode (with caching)
	engine, err := echotemplates.New(echotemplates.Config{
		Source:    source,
		DevMode:   false,
		CacheSize: 100,
	})
	if err != nil {
		log.Fatal(err)
	}

	// Generate messages
	messages, err := engine.Generate("example", map[string]any{
		"topic": "AI",
	})
	if err != nil {
		log.Fatal(err)
	}

	for _, msg := range messages {
		fmt.Printf("Role: %s, Content: %s\n", msg.Role, msg.Content)
	}
}

func NewEmbedSource

func NewEmbedSource(embedFS embed.FS, rootDir string) *EmbedSource

NewEmbedSource creates a new embedded template source

func (*EmbedSource) List

func (s *EmbedSource) List() ([]string, error)

List returns all available template paths

func (*EmbedSource) Open

func (s *EmbedSource) Open(path string) (io.ReadCloser, error)

Open returns a reader for the template content

func (*EmbedSource) ResolveImport

func (s *EmbedSource) ResolveImport(importPath, currentPath string) string

ResolveImport allows customizing import resolution

func (*EmbedSource) Stat

func (s *EmbedSource) Stat(path string) (TemplateInfo, error)

Stat returns information about a template

func (*EmbedSource) StopWatch

func (s *EmbedSource) StopWatch() error

StopWatch is a no-op for embedded templates

func (*EmbedSource) Watch

func (s *EmbedSource) Watch() (<-chan string, error)

Watch returns nil as embedded templates don't change

type FileSystemSource

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

FileSystemSource implements TemplateSource for filesystem-based templates

Example
package main

import (
	"fmt"
	"log"

	echotemplates "github.com/mkozhukh/echo-templates"
)

func main() {
	// Create a filesystem source
	source, err := echotemplates.NewFileSystemSource("./templates")
	if err != nil {
		log.Fatal(err)
	}

	// Create engine with dev mode enabled (no caching, file watching)
	engine, err := echotemplates.New(echotemplates.Config{
		Source:  source,
		DevMode: true,
	})
	if err != nil {
		log.Fatal(err)
	}

	// Generate messages
	messages, err := engine.Generate("hello", map[string]any{
		"name": "World",
	})
	if err != nil {
		log.Fatal(err)
	}

	for _, msg := range messages {
		fmt.Printf("Role: %s, Content: %s\n", msg.Role, msg.Content)
	}
}

func NewFileSystemSource

func NewFileSystemSource(rootDir string) (*FileSystemSource, error)

NewFileSystemSource creates a new filesystem template source

func (*FileSystemSource) List

func (s *FileSystemSource) List() ([]string, error)

List returns all available template paths

func (*FileSystemSource) Open

func (s *FileSystemSource) Open(path string) (io.ReadCloser, error)

Open returns a reader for the template content

func (*FileSystemSource) ResolveImport

func (s *FileSystemSource) ResolveImport(importPath, currentPath string) string

ResolveImport allows customizing import resolution

func (*FileSystemSource) Stat

func (s *FileSystemSource) Stat(path string) (TemplateInfo, error)

Stat returns information about a template

func (*FileSystemSource) StopWatch

func (s *FileSystemSource) StopWatch() error

StopWatch stops watching for changes

func (*FileSystemSource) Watch

func (s *FileSystemSource) Watch() (<-chan string, error)

Watch starts watching for changes

type GenerateOptions

type GenerateOptions struct {
	// AllowMissingVars determines if missing placeholders cause errors
	AllowMissingVars bool

	// StrictMode enables strict parsing (no undefined imports, etc)
	StrictMode bool

	// DisableCache bypasses cache for this generation
	DisableCache bool
}

GenerateOptions configures template generation behavior

type ImportError

type ImportError struct {
	ImportPath string
	Template   string
	Cause      error
}

ImportError indicates a failure during template import

func (*ImportError) Error

func (e *ImportError) Error() string

type MockSource added in v0.2.0

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

MockSource implements TemplateSource for testing purposes using an in-memory map

func NewMockSource added in v0.2.0

func NewMockSource(templates map[string]string) *MockSource

NewMockSource creates a new mock template source with the given templates

func (*MockSource) List added in v0.2.0

func (m *MockSource) List() ([]string, error)

List returns all available template paths

func (*MockSource) Open added in v0.2.0

func (m *MockSource) Open(path string) (io.ReadCloser, error)

Open returns a reader for the template content

func (*MockSource) ResolveImport added in v0.2.0

func (m *MockSource) ResolveImport(importPath, currentPath string) string

ResolveImport returns empty string - no custom import resolution

func (*MockSource) Stat added in v0.2.0

func (m *MockSource) Stat(path string) (TemplateInfo, error)

Stat returns information about a template

func (*MockSource) StopWatch added in v0.2.0

func (m *MockSource) StopWatch() error

StopWatch is a no-op for mock

func (*MockSource) Watch added in v0.2.0

func (m *MockSource) Watch() (<-chan string, error)

Watch returns nil channel - watching not supported for mock

type ParseError

type ParseError struct {
	Template string
	Line     int
	Message  string
}

ParseError indicates a template parsing error

func (*ParseError) Error

func (e *ParseError) Error() string

type TemplateEngine

type TemplateEngine interface {
	// Generate creates messages from a template
	// If name doesn't contain .md suffix, it will be added automatically
	Generate(name string, vars map[string]any, opts ...GenerateOptions) ([]echo.Message, error)

	// GenerateWithMetadata creates messages and returns template metadata
	GenerateWithMetadata(name string, vars map[string]any, opts ...GenerateOptions) ([]echo.Message, map[string]any, error)

	// ClearCache removes cached templates (useful for development)
	ClearCache()

	// ValidateTemplate checks if a template is valid without generating messages
	ValidateTemplate(name string) error

	// GetTemplateVariables returns all variable names used in a template
	GetTemplateVariables(name string) ([]string, error)

	// TemplateExists checks if a template file exists
	TemplateExists(name string) bool

	// ListTemplates returns all available template paths relative to RootDir
	ListTemplates() ([]string, error)
}

TemplateEngine manages template loading and processing

func New

func New(config Config) (TemplateEngine, error)

New creates a new template engine

type TemplateInfo

type TemplateInfo struct {
	// Path is the template path
	Path string

	// ModTime is the modification time
	ModTime time.Time

	// Size is the template size in bytes
	Size int64

	// IsDir indicates if this is a directory
	IsDir bool
}

TemplateInfo contains information about a template

type TemplateNotFoundError

type TemplateNotFoundError struct {
	Name string
	Path string
}

TemplateNotFoundError indicates that a template file was not found

func (*TemplateNotFoundError) Error

func (e *TemplateNotFoundError) Error() string

type TemplateSource

type TemplateSource interface {
	// Open returns a reader for the template content
	Open(path string) (io.ReadCloser, error)

	// Stat returns information about a template
	Stat(path string) (TemplateInfo, error)

	// List returns all available template paths
	List() ([]string, error)

	// Watch starts watching for changes if supported
	// The returned channel will receive paths of changed templates
	// Returns nil if watching is not supported
	Watch() (<-chan string, error)

	// StopWatch stops watching for changes
	StopWatch() error

	// ResolveImport allows customizing import resolution
	// Given an import path and the current template path, returns the resolved path
	// Return empty string to use default resolution
	ResolveImport(importPath, currentPath string) string
}

TemplateSource abstracts the source of templates (filesystem, embedded, etc.)

type VariableError

type VariableError struct {
	Variable string
	Template string
}

VariableError indicates a missing or invalid variable

func (*VariableError) Error

func (e *VariableError) Error() string

Jump to

Keyboard shortcuts

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