# 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