UNPKG

@ctrl/golang-template

Version:
136 lines (99 loc) 4.15 kB
# golang-template [![npm](https://img.shields.io/npm/v/@ctrl/golang-template.svg?maxAge=3600)](https://www.npmjs.com/package/@ctrl/golang-template) > TypeScript implementation of a subset of the [Go template](https://pkg.go.dev/text/template) syntax. ## Install ```sh npm install @ctrl/golang-template ``` ## Usage ```ts import { compile, parse } from '@ctrl/golang-template'; // One-shot parse('{{ if .keywords }}{{ .keywords }}!!{{ else }}nothing{{ end }}', { keywords: '123' }); // '123!!' // Compile once, render many times (better for hot paths) const tmpl = compile('{{ if .name }}Hello {{ .name }}!{{ end }}'); tmpl.render({ name: 'World' }); // 'Hello World!' tmpl.render({ name: 'Alice' }); // 'Hello Alice!' ``` ## Supported syntax ### Variables ```ts parse('{{ .foo }}', { foo: 'bar' }); // 'bar' parse('{{ .user.name }}', { user: { name: 'Alice' } }); // 'Alice' ``` ### if / else ```ts parse('{{ if .keywords }}{{ .keywords }}{{ else }}nothing{{ end }}', { keywords: 'swag' }); // 'swag' ``` ### if with and / or / not ```ts parse('{{ if and .a .b }}both{{ else }}no{{ end }}', { a: 'x', b: 'y' }); // 'both' parse('{{ if or .a .b }}either{{ else }}neither{{ end }}', { a: '', b: 'y' }); // 'either' parse('{{ if not .disabled }}enabled{{ end }}', { disabled: false }); // 'enabled' ``` ### with Sets `.` to the value for the duration of the block; skips the block if the value is falsy. ```ts parse('{{ with .user }}Hello {{ . }}!{{ end }}', { user: 'World' }); // 'Hello World!' parse('{{ with .user }}Hello {{ . }}{{ else }}nobody{{ end }}', { user: '' }); // 'nobody' ``` ### range ```ts const categories = ['a', 'b', 'c']; parse('{{ range .categories }}{{ . }};{{ end }}', { categories }); // 'a;b;c;' const items = [{ name: 'alice' }, { name: 'bob' }]; parse('{{ range .items }}{{ .name }};{{ end }}', { items }); // 'alice;bob;' ``` Inside `range`, `{{ .Field }}` resolves against the current item only. `{{ $.RootVar }}` is still unsupported. ### index ```ts const data = { object: { value: 'foo' }, array: ['bar'], }; parse('{{ index .object "value" }}', data); // 'foo' parse('{{ index .array 0 }}', data); // 'bar' ``` ### join † ```ts const categories = ['a', 'b', 'c']; parse('{{ join .categories "," }}', { categories }); // 'a,b,c' ``` ### re_replace † ```ts parse('{{ re_replace .category "[^a-zA-Z0-9]+" "%" }}', { category: '123$special' }); // '123%special' ``` † Non-standard extension, not available in Go's `text/template`. ## Compatibility | Feature | Supported | | -------------------------------------------------------------- | --------- | | `{{ .Variable }}` | ✅ | | `{{ .nested.path }}` | ✅ | | `{{ if }}` / `{{ else }}` / `{{ end }}` | ✅ | | `{{ if and .a .b }}` / `{{ if or .a .b }}` / `{{ if not .a }}` | ✅ | | `{{ with }}` | ✅ | | `{{ range }}` with `{{ . }}` | ✅ | | `{{ index .arr 0 }}` / `{{ index .obj "key" }}` | ✅ | | `{{ join }}` (extension) | ✅ | | `{{ re_replace }}` (extension) | ✅ | | `{{ range }}` with `{{ .Field }}` on items | ✅ | | `{{ if eq .a .b }}` / `{{ if gt .a .b }}` etc. | ❌ | | `{{ $var := .val }}` variable assignment | ❌ | | `{{ $.RootVar }}` from inside range/with | ❌ | | `{{ len .val }}` | ❌ | | `{{ printf }}` / `{{ html }}` / `{{ js }}` | ❌ | | `{{ template }}` / `{{ block }}` | ❌ | ## Warnings Do not render fully untrusted templates. The `re_replace` tag runs template-provided JavaScript regex patterns, so malicious or careless patterns can still cause excessive CPU use.