# Go Text Template Directives - Implementation Specification for C#
## Overview
This specification defines the behavior of `define`, `template`, and `block` directives from Go's text/template package for implementation in C#.
## Core Concepts
### Template Registry
- Maintain a dictionary/map of template names to compiled template objects
- Templates can be defined at parse time or runtime
- Template lookup is case-sensitive
- Nested template definitions are allowed
### Context Management
- Each template execution has a data context (equivalent to Go's "dot" `.`)
- Context can be passed explicitly to template invocations
- Default context is the current execution context
## 1. `define` Directive
### Syntax
```
{{define "templateName"}}content{{end}}
```
### Behavior
- Registers a named template in the template registry
- Does NOT execute the template immediately
- Template content is parsed and compiled for later use
- Can be defined anywhere in the template (top-level or nested)
- Multiple definitions with the same name: last definition wins
### Implementation Requirements
```csharp
// Pseudo-interface for implementation
interface ITemplateDirective
{
void ParseDefine(string templateName, string templateContent);
void RegisterTemplate(string name, CompiledTemplate template);
}
```
### Example Processing
Input: `{{define "header"}}
{{.Title}}
{{end}}`
- Extract name: "header"
- Extract content: `{{.Title}}
`
- Compile content as separate template
- Register in template registry with key "header"
## 2. `template` Directive
### Syntax
```
{{template "templateName"}}
{{template "templateName" pipeline}}
```
### Behavior
- Executes a previously defined template by name
- If no pipeline provided, uses current context (`.`)
- If pipeline provided, evaluates pipeline and uses result as context
- Throws error if template name not found
- Output is inserted at the current position
### Implementation Requirements
```csharp
// Pseudo-interface for implementation
interface ITemplateExecution
{
string ExecuteTemplate(string templateName, object context = null);
bool TemplateExists(string templateName);
}
```
### Context Handling
- `{{template "name"}}` → Execute with current context
- `{{template "name" .User}}` → Execute with `.User` as context
- `{{template "name" "literal"}}` → Execute with string literal as context
- `{{template "name" pipeline}}` → Execute with pipeline result as context
### Error Conditions
- Template not found → Runtime error
- Template execution error → Propagate error up
## 3. `block` Directive
### Syntax
```
{{block "templateName" pipeline}}default content{{end}}
```
### Behavior
- Combination of `define` + `template`
- Defines a template with the given name and content
- Immediately executes the template with the provided pipeline
- If template with same name already exists, uses existing template instead of default content
- Enables template inheritance/override pattern
### Implementation Requirements
```csharp
// Pseudo-interface for implementation
interface IBlockDirective
{
string ProcessBlock(string templateName, object context, string defaultContent);
}
```
### Processing Logic
```csharp
// Pseudo-code for block processing
string ProcessBlock(string name, object context, string defaultContent)
{
if (TemplateRegistry.ContainsKey(name))
{
// Use existing template (override case)
return ExecuteTemplate(name, context);
}
else
{
// Define and execute default template
var compiledDefault = CompileTemplate(defaultContent);
TemplateRegistry[name] = compiledDefault;
return ExecuteTemplate(name, context);
}
}
```
## Implementation Details
### Template Compilation
- Templates should be compiled to an intermediate representation
- Support nested template calls
- Handle variable scoping correctly
- Preserve line numbers for error reporting
### Error Handling
```csharp
public class TemplateError : Exception
{
public string TemplateName { get; set; }
public int LineNumber { get; set; }
public string DirectiveType { get; set; } // "template", "define", "block"
}
```
### Thread Safety
- Template registry should be thread-safe for concurrent access
- Template execution should be thread-safe
- Consider using ConcurrentDictionary for template storage
### Memory Management
- Compiled templates should be cached efficiently
- Consider template cleanup/eviction strategies for long-running applications
## Usage Patterns
### Basic Template Definition and Usage
```go
// Go template equivalent
{{define "greeting"}}Hello, {{.Name}}!{{end}}
{{template "greeting" .User}}
```
### Template Inheritance with Blocks
```go
// Base template
{{block "title" .}}Default Title{{end}}
{{block "content" .}}Default content{{end}}
// Child template (parsed later)
{{define "title"}}Custom Title: {{.PageTitle}}{{end}}
{{define "content"}}Custom content: {{.Body}}{{end}}
```
### Expected C# API Usage
```csharp
var engine = new GoTemplateEngine();
// Parse template with definitions
engine.ParseTemplate("base", baseTemplateContent);
engine.ParseTemplate("child", childTemplateContent);
// Execute with data
var result = engine.ExecuteTemplate("base", new {
PageTitle = "My Page",
Body = "Content here"
});
```
## Test Cases
### Define Directive
- Define template and verify it's registered
- Define template with same name twice (last wins)
- Define nested templates
- Define template with complex content including other directives
### Template Directive
- Execute existing template with current context
- Execute existing template with explicit context
- Execute non-existent template (should error)
- Execute template that calls other templates
### Block Directive
- Block with no existing template (uses default)
- Block with existing template (uses existing, ignores default)
- Block with complex pipeline context
- Nested blocks
### Integration Tests
- Template inheritance scenarios
- Circular template references (should error)
- Deep nesting of template calls
- Performance with large numbers of templates