@ctrl/golang-template
Version:
Basic golang template parsing in js
136 lines (99 loc) • 4.15 kB
Markdown
# golang-template [](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.