{"id":24325817,"url":"https://github.com/alesr/templator","last_synced_at":"2025-07-18T22:02:17.618Z","repository":{"id":272514164,"uuid":"916774852","full_name":"alesr/templator","owner":"alesr","description":"A type-safe HTML template rendering engine for Go","archived":false,"fork":false,"pushed_at":"2025-06-01T13:09:22.000Z","size":71,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-08T16:40:02.602Z","etag":null,"topics":["code-generation","go-template","template"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alesr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-14T18:29:33.000Z","updated_at":"2025-06-01T13:54:11.000Z","dependencies_parsed_at":"2025-06-08T16:44:33.241Z","dependency_job_id":null,"html_url":"https://github.com/alesr/templator","commit_stats":null,"previous_names":["alesr/templator"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/alesr/templator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alesr%2Ftemplator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alesr%2Ftemplator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alesr%2Ftemplator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alesr%2Ftemplator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alesr","download_url":"https://codeload.github.com/alesr/templator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alesr%2Ftemplator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265844015,"owners_count":23837502,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generation","go-template","template"],"created_at":"2025-01-17T20:29:25.096Z","updated_at":"2025-07-18T22:02:17.560Z","avatar_url":"https://github.com/alesr.png","language":"Go","funding_links":[],"categories":["Template Engines","模板引擎"],"sub_categories":["HTTP Clients","HTTP客户端"],"readme":"# Templator\n\n[![codecov](https://codecov.io/gh/alesr/templator/graph/badge.svg?token=HiYBMXeIbg)](https://codecov.io/gh/alesr/templator)\n[![Go Report Card](https://goreportcard.com/badge/github.com/alesr/templator)](https://goreportcard.com/report/github.com/alesr/templator)\n[![Go Reference](https://pkg.go.dev/badge/github.com/alesr/templator.svg)](https://pkg.go.dev/github.com/alesr/templator)\n\nA type-safe HTML template rendering engine for Go.\n\n\u003e **Note**: This is an experimental project in active development. While it's stable enough for use, expect possible API changes. Feedback and contributions are welcome!\n\n## Table of Contents\n\n- [Problem Statement](#problem-statement)\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Usage Examples](#usage-examples)\n- [Template Generation](#template-generation)\n- [Configuration](#configuration)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Problem Statement\n\nGo's built-in template package lacks type safety, which can lead to runtime errors when template data doesn't match what the template expects. For example:\n\n```go\n// Traditional approach with Go templates\ntmpl := template.Must(template.ParseFiles(\"home.html\"))\n\n// This compiles but will fail at runtime if the template expects different fields\ntmpl.Execute(w, struct {\n    WrongField string\n    MissingRequired int\n}{})\n\n// No compile-time checks for:\n// - Missing required fields\n// - Wrong field types\n// - Typos in field names\n```\n\nTemplator solves this by providing compile-time type checking for your templates:\n\n```go\n// Define your template data type\ntype HomeData struct {\n    Title   string\n    Content string\n}\n\n// Initialize registry with type parameter\nreg, _ := templator.NewRegistry[HomeData](fs)\n\n// Get type-safe handler and execute template\nhome, _ := reg.GetHome()\nhome.Execute(ctx, w, HomeData{\n    Title: \"Welcome\",\n    Content: \"Hello\",\n})\n\n// Won't compile - wrong data structure\nhome.Execute(ctx, w, struct{\n    WrongField string\n}{})\n```\n\n## Features\n\n- Type-safe template execution with generics\n- Concurrent-safe template management\n- Custom template functions support\n- Clean and simple API\n- HTML escaping by default\n\n## Installation\n\n```bash\ngo install github.com/alesr/templator\n```\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"log\"\n    \"os\"\n\n    \"github.com/alesr/templator\"\n)\n\n// Define your template data\ntype HomeData struct {\n    Title   string\n    Content string\n}\n\nfunc main() {\n    // Use the filesystem of your choice\n    fs := os.DirFS(\".\")\n\n    // Initialize registry with your data type\n    reg, err := templator.NewRegistry[HomeData](fs)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Get type-safe handler for home template\n    home, err := reg.GetHome()\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Execute template with proper data\n    err = home.Execute(context.Background(), os.Stdout, HomeData{\n        Title:   \"Welcome\",\n        Content: \"Hello, World!\",\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n}\n```\n\n## Usage Examples\n\n### Type-Safe Templates\n\n```go\n// Define different data types for different templates\ntype HomeData struct {\n    Title    string\n    Content  string\n}\n\ntype AboutData struct {\n    Company  string\n    Year     int\n}\n\n// Create registries for different template types\nhomeReg := templator.NewRegistry[HomeData](fs)\naboutReg := templator.NewRegistry[AboutData](fs)\n\n// Get handlers\nhome, _ := homeReg.GetHome()\nabout, _ := aboutReg.GetAbout()\n\n// Type safety enforced at compile time\nhome.Execute(ctx, w, HomeData{...})  // ✅ Compiles\nhome.Execute(ctx, w, AboutData{...}) // ❌ Compile error\n```\n\n### Using Template Functions\n\n```go\n// Define your custom functions\nfuncMap := template.FuncMap{\n    \"upper\": strings.ToUpper,\n    \"lower\": strings.ToLower,\n}\n\n// Create registry with functions\nreg, err := templator.NewRegistry[PageData](fs, \n    templator.WithTemplateFuncs[PageData](funcMap))\n\n// Use functions in your templates:\n// \u003ch1\u003e{{.Title | upper}}\u003c/h1\u003e\n```\n\n### File System Support\n\n```go\n// Embedded FS\n//go:embed templates/*\nvar embedFS embed.FS\nreg := templator.NewRegistry[HomeData](embedFS)\n\n// OS File System\nreg := templator.NewRegistry[HomeData](os.DirFS(\"./templates\"))\n\n// In-Memory (testing)\nfsys := fstest.MapFS{\n    \"templates/home.html\": \u0026fstest.MapFile{\n        Data: []byte(`\u003ch1\u003e{{.Title}}\u003c/h1\u003e`),\n    },\n}\nreg := templator.NewRegistry[HomeData](fsys)\n```\n\n### Field Validation\n\n```go\ntype ArticleData struct {\n    Title    string    // Only these two fields\n    Content  string    // are allowed in templates\n}\n\n// Enable validation during registry creation\nreg := templator.NewRegistry[ArticleData](\n    fs,\n    templator.WithFieldValidation(ArticleData{}),\n)\n\n// Example templates:\n\n// valid.html:\n// \u003ch1\u003e{{.Title}}\u003c/h1\u003e           // ✅ OK - Title exists in ArticleData\n// \u003cp\u003e{{.Content}}\u003c/p\u003e           // ✅ OK - Content exists in ArticleData\n\n// invalid.html:\n// \u003ch1\u003e{{.Author}}\u003c/h1\u003e          // ❌ Error - Author field doesn't exist\n// \u003cp\u003e{{.PublishedAt}}\u003c/p\u003e       // ❌ Error - PublishedAt field doesn't exist\n\n// Using the templates:\nhandler, err := reg.Get(\"valid\")    // ✅ Success - all fields exist\nif err != nil {\n    log.Fatal(err)\n}\n\nhandler, err := reg.Get(\"invalid\")  // ❌ Error: \"template 'invalid' validation error: Author - field 'Author' not found in type ArticleData\"\n\n// The validation error provides:\n// - Template name\n// - Invalid field path\n// - Detailed error message\nif validErr, ok := err.(*templator.ValidationError); ok {\n    fmt.Printf(\"Template: %s\\n\", validErr.TemplateName)\n    fmt.Printf(\"Invalid field: %s\\n\", validErr.FieldPath)\n    fmt.Printf(\"Error: %v\\n\", validErr.Err)\n}\n```\n\nThis validation happens when loading the template, not during execution, helping catch field mismatches early in development.\n\n## Template Generation\n\nTemplates are automatically discovered and type-safe methods are generated:\n\n```zsh\ntemplates/\n├── home.html           -\u003e reg.GetHome()\n├── about.html          -\u003e reg.GetAbout()\n└── components/\n    └── header.html     -\u003e reg.GetComponentsHeader()\n\n# Generate methods\ngo generate ./...\n```\n\nThe generation process creates a `templator_methods.go` file containing type-safe method handlers for each template. For example:\n\n```go\n// Code generated by go generate; DO NOT EDIT.\nfunc (r *Registry[T]) GetHome() (*Handler[T], error) {\n    return r.Get(\"home\")\n}\n\nfunc (r *Registry[T]) GetAbout() (*Handler[T], error) {\n    return r.Get(\"about\")\n}\n```\n\nThis file is automatically generated and should not be manually edited.\n\n## Configuration\n\n```go\nreg, err := templator.NewRegistry[HomeData](\n    fs,\n    // Custom template directory\n    templator.WithTemplatesPath[HomeData](\"views\"),\n    // Enable field validation\n    templator.WithFieldValidation(HomeData{}),\n)\n```\n\n### Development Requirements\n\n- Go 1.21 or higher\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falesr%2Ftemplator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falesr%2Ftemplator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falesr%2Ftemplator/lists"}