miki-template 1.3.3 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +16 -0
- package/.github/release-notes/v1.3.1.md +55 -55
- package/.github/release-notes/v1.3.3.md +77 -0
- package/.github/workflows/ci.yml +38 -54
- package/.github/workflows/release.yml +106 -0
- package/AGENT.md +71 -71
- package/API_REFERENCE.md +314 -314
- package/CHANGELOG.md +173 -169
- package/CODE_OF_CONDUCT.md +14 -14
- package/CONTRIBUTING.md +27 -27
- package/README.md +342 -321
- package/ROADMAP.md +40 -40
- package/benchmarks/report.json +16 -16
- package/benchmarks/run.js +49 -49
- package/benchmarks/stress.mjs +647 -647
- package/benchmarks/templates/large.dtpl +7 -7
- package/benchmarks/templates/medium.dtpl +3 -3
- package/benchmarks/templates/small.dtpl +7 -7
- package/context/component.md +109 -109
- package/context/prd.md +131 -131
- package/context/project-structure.md +33 -33
- package/dir/base.html +22 -22
- package/dir/cmpnt.html +10 -10
- package/dir/footer.html +2 -2
- package/dir/home.html +80 -80
- package/dir/index.html +80 -0
- package/dir/navbar.html +8 -8
- package/docs/README.md +18 -18
- package/docs/advanced_usage.md +71 -71
- package/docs/api.md +119 -119
- package/docs/filters.md +708 -708
- package/docs/installation.md +106 -106
- package/docs/overview.md +79 -57
- package/docs/partialdef.md +70 -70
- package/docs/security.md +27 -27
- package/docs/tags.md +673 -673
- package/docs/usage.md +646 -646
- package/eslint.config.mjs +42 -42
- package/ex.mjs +34 -32
- package/live-test/package-lock.json +915 -0
- package/live-test/package.json +9 -0
- package/live-test/server.js +14 -0
- package/live-test/views/base.html +8 -0
- package/live-test/views/child.html +7 -0
- package/live-test/views/index.html +1 -0
- package/miki-template-extension/.github/workflows/ci.yml +116 -116
- package/miki-template-extension/.vscodeignore +7 -7
- package/miki-template-extension/CHANGELOG.md +99 -99
- package/miki-template-extension/LICENSE +21 -21
- package/miki-template-extension/README.md +273 -273
- package/miki-template-extension/extension.js +1013 -1013
- package/miki-template-extension/icon.svg +10 -10
- package/miki-template-extension/package.json +280 -280
- package/miki-template-extension/snippets/miki-template.json +717 -717
- package/miki-template-extension/syntaxes/language-configuration.json +114 -114
- package/miki-template-extension/syntaxes/miki-template.tmLanguage.json +355 -355
- package/miki-template-extension/tests/grammar-tests.json +162 -162
- package/miki-template-extension/tests/run-grammar-tests.js +82 -82
- package/package.json +40 -34
- package/sample-app/package-lock.json +901 -0
- package/sample-app/package.json +9 -0
- package/sample-app/server.js +14 -0
- package/sample-app/views/index.html +1 -0
- package/scripts/build-vsix.js +129 -129
- package/scripts/build-vsix.ps1 +15 -15
- package/snippets/miki-template.json +177 -177
- package/src/asyncRender.js +20 -20
- package/src/cache.js +80 -80
- package/src/context.js +126 -126
- package/src/context_processors.js +48 -48
- package/src/esm.mjs +89 -84
- package/src/filters.js +975 -975
- package/src/i18n.js +171 -171
- package/src/index.js +1112 -940
- package/src/lexer.js +114 -114
- package/src/libraries.js +371 -371
- package/src/parser.js +270 -270
- package/src/security.js +53 -53
- package/src/tags/control.js +719 -719
- package/src/tags/extra.js +154 -154
- package/src/tags/helpers.js +26 -26
- package/src/tags/i18n.js +256 -256
- package/src/tags/inheritance.js +335 -335
- package/src/tags/registry.js +18 -18
- package/src/tags/util.js +400 -400
- package/src/types.d.ts +107 -107
- package/syntaxes/language-configuration.json +26 -26
- package/syntaxes/miki-template.tmLanguage.json +146 -146
- package/tests/asyncRender.test.js +17 -17
- package/tests/base.html +6 -6
- package/tests/child.html +3 -3
- package/tests/context_processors.test.js +13 -13
- package/tests/esm.test.mjs +61 -61
- package/tests/filters.test.js +254 -254
- package/tests/finder-appdirs.test.js +19 -0
- package/tests/finder.test.js +17 -0
- package/tests/fixtures/views/nested/index.html +1 -0
- package/tests/fixtures/views/partial.html +1 -0
- package/tests/fixtures/views/sub/deepfile.html +1 -0
- package/tests/fixtures/views-appdirs/product/site/detail.html +1 -0
- package/tests/include_security.test.js +9 -9
- package/tests/integration/README.md +32 -32
- package/tests/integration/features.test.cjs +1681 -1681
- package/tests/integration/features.test.mjs +1697 -1697
- package/tests/integration/finder.esm.test.mjs +13 -0
- package/tests/integration/templates/base.miki +6 -6
- package/tests/integration/templates/child.miki +6 -6
- package/tests/integration/templates/index.html +17 -17
- package/tests/lexer.test.js +45 -45
- package/tests/parser.test.js +57 -57
- package/tests/partial.html +1 -1
- package/tests/partialdef.test.js +79 -79
- package/tests/production_checks.js +57 -57
- package/tests/security.test.js +28 -28
- package/tests/tags.test.js +233 -233
package/API_REFERENCE.md
CHANGED
|
@@ -1,314 +1,314 @@
|
|
|
1
|
-
# API Reference - miki-template
|
|
2
|
-
|
|
3
|
-
This document provides complete details for the public APIs exported by the **miki-template** engine — a Django-style template engine for Node.js and Express.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Core Exports
|
|
8
|
-
|
|
9
|
-
```javascript
|
|
10
|
-
const {
|
|
11
|
-
compile,
|
|
12
|
-
render,
|
|
13
|
-
asyncRender,
|
|
14
|
-
__express,
|
|
15
|
-
clearCache,
|
|
16
|
-
registerTag,
|
|
17
|
-
registerFilter,
|
|
18
|
-
registerHelper,
|
|
19
|
-
registerContextProcessor,
|
|
20
|
-
SafeString,
|
|
21
|
-
markSafe,
|
|
22
|
-
isSafe,
|
|
23
|
-
escapeHtml
|
|
24
|
-
} = require('miki-template');
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
### `compile(templateStr, options)`
|
|
30
|
-
|
|
31
|
-
Compiles a raw template string into a reusable compiled template object. The compiled template caches its AST internally.
|
|
32
|
-
|
|
33
|
-
**Parameters**:
|
|
34
|
-
- `templateStr` (string): The raw template string to compile.
|
|
35
|
-
- `options` (object): Config parameters:
|
|
36
|
-
- `views` (string|string[]): Directories to search for templates when using `extends` or `include`.
|
|
37
|
-
- `staticUrl` (string): Prefix for the `{% static %}` tag. Defaults to `/static/`.
|
|
38
|
-
- `urlHelper` (function): Custom URL resolver for `{% url %}` tag.
|
|
39
|
-
|
|
40
|
-
**Returns**: An object containing:
|
|
41
|
-
- `render(context)` — Synchronously renders the template.
|
|
42
|
-
- `asyncRender(context)` — Returns a Promise for async rendering.
|
|
43
|
-
- `renderBlock(blockName, context)` — Renders a specific block by name.
|
|
44
|
-
- `renderPartial(partialName, context)` — Renders a defined partial by name.
|
|
45
|
-
|
|
46
|
-
**Example**:
|
|
47
|
-
```javascript
|
|
48
|
-
const { compile } = require('miki-template');
|
|
49
|
-
|
|
50
|
-
const template = compile('Hello {{ name }}!');
|
|
51
|
-
const output = template.render({ name: 'World' });
|
|
52
|
-
console.log(output); // Hello World!
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
### `render(templateStr, context, options)`
|
|
58
|
-
|
|
59
|
-
One-step convenience function that compiles and renders a template.
|
|
60
|
-
|
|
61
|
-
**Parameters**:
|
|
62
|
-
- `templateStr` (string): Raw template string.
|
|
63
|
-
- `context` (object): Variables available to the template.
|
|
64
|
-
- `options` (object): Same as `compile()` options.
|
|
65
|
-
|
|
66
|
-
**Returns**: Rendered HTML string.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
### `asyncRender(templateStr, context, options)`
|
|
71
|
-
|
|
72
|
-
Asynchronous rendering for templates with async helpers or async context processors.
|
|
73
|
-
|
|
74
|
-
**Parameters**: Same as `render()`.
|
|
75
|
-
|
|
76
|
-
**Returns**: `Promise<string>` — resolved rendered HTML.
|
|
77
|
-
|
|
78
|
-
**Example**:
|
|
79
|
-
```javascript
|
|
80
|
-
const { asyncRender } = require('miki-template');
|
|
81
|
-
const html = await asyncRender('Hello {{ name }}!', { name: 'Async' });
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
### `__express(filePath, options, callback)`
|
|
87
|
-
|
|
88
|
-
Express-compatible view engine adapter. Use with `app.engine()`.
|
|
89
|
-
|
|
90
|
-
**Parameters**:
|
|
91
|
-
- `filePath` (string): Absolute path to the template file.
|
|
92
|
-
- `options` (object): Express `res.render()` context (view engine strips `_locals`, `settings`, and other Express internals).
|
|
93
|
-
- `callback` (function): Node.js callback `(err, html)`.
|
|
94
|
-
|
|
95
|
-
**Example**:
|
|
96
|
-
```javascript
|
|
97
|
-
const express = require('express');
|
|
98
|
-
const { __express } = require('miki-template');
|
|
99
|
-
|
|
100
|
-
const app = express();
|
|
101
|
-
app.engine('html', __express);
|
|
102
|
-
app.set('view engine', 'html');
|
|
103
|
-
app.set('views', './views');
|
|
104
|
-
|
|
105
|
-
app.get('/', (req, res) => {
|
|
106
|
-
res.render('home', { title: 'Home Page' });
|
|
107
|
-
});
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
### `registerTag(name, parserFn)`
|
|
113
|
-
|
|
114
|
-
Registers a custom block tag parser. Must be called **before** compiling templates that use the tag.
|
|
115
|
-
|
|
116
|
-
**Parameters**:
|
|
117
|
-
- `name` (string): Tag identifier word (e.g. `mytag` for `{% mytag %}`).
|
|
118
|
-
- `parserFn` (function): `(tagContent: string, parser: Parser) => ASTNode`. Receives the raw tag content and the parser instance.
|
|
119
|
-
|
|
120
|
-
**Returns**: `undefined`.
|
|
121
|
-
|
|
122
|
-
**Example**:
|
|
123
|
-
```javascript
|
|
124
|
-
const { registerTag } = require('miki-template');
|
|
125
|
-
|
|
126
|
-
registerTag('greet', (tagContent, parser) => {
|
|
127
|
-
const name = tagContent.slice(5).trim(); // strip 'greet'
|
|
128
|
-
return {
|
|
129
|
-
render: (context) => `Hello ${context.get(name) || 'Guest'}!`
|
|
130
|
-
};
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// In template: {% greet user.name %}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
### `registerFilter(name, filterFn)`
|
|
139
|
-
|
|
140
|
-
Registers a custom filter function.
|
|
141
|
-
|
|
142
|
-
**Parameters**:
|
|
143
|
-
- `name` (string): Filter name used after the pipe `|`.
|
|
144
|
-
- `filterFn` (function): `(value: any, arg?: any) => any`. Receives the filtered value and optional argument.
|
|
145
|
-
|
|
146
|
-
**Returns**: `undefined`.
|
|
147
|
-
|
|
148
|
-
**Example**:
|
|
149
|
-
```javascript
|
|
150
|
-
const { registerFilter } = require('miki-template');
|
|
151
|
-
|
|
152
|
-
registerFilter('reverse', (val) => {
|
|
153
|
-
return String(val).split('').reverse().join('');
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// In template: {{ name|reverse }}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
### `registerHelper(name, fn)`
|
|
162
|
-
|
|
163
|
-
Registers a custom block helper tag. The helper receives the **rendered** inner content as a string.
|
|
164
|
-
|
|
165
|
-
**Parameters**:
|
|
166
|
-
- `name` (string): Tag name (e.g. `markdown` creates `{% markdown %}...{% endmarkdown %}`).
|
|
167
|
-
- `fn` (function): `(innerContent: string, context: Context) => string | Promise<string>`.
|
|
168
|
-
|
|
169
|
-
**Returns**: `undefined`.
|
|
170
|
-
|
|
171
|
-
**Example**:
|
|
172
|
-
```javascript
|
|
173
|
-
const { registerHelper } = require('miki-template');
|
|
174
|
-
const markdownIt = require('markdown-it')();
|
|
175
|
-
registerHelper('markdown', (content) => markdownIt.render(content));
|
|
176
|
-
|
|
177
|
-
// In template:
|
|
178
|
-
// {% markdown %}
|
|
179
|
-
// # Hello
|
|
180
|
-
// {% endmarkdown %}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
### `registerContextProcessor(fn)`
|
|
186
|
-
|
|
187
|
-
Adds a context processor function. Similar to Django's custom context processors.
|
|
188
|
-
|
|
189
|
-
**Parameters**:
|
|
190
|
-
- `fn` (function): `(context: object) => object | undefined`. Receives the render context and returns extra key-value pairs to merge in.
|
|
191
|
-
|
|
192
|
-
**Returns**: `undefined`.
|
|
193
|
-
|
|
194
|
-
**Example**:
|
|
195
|
-
```javascript
|
|
196
|
-
const { registerContextProcessor } = require('miki-template');
|
|
197
|
-
|
|
198
|
-
registerContextProcessor((ctx) => ({
|
|
199
|
-
siteName: 'MySite',
|
|
200
|
-
currentYear: new Date().getFullYear()
|
|
201
|
-
}));
|
|
202
|
-
|
|
203
|
-
// Available in all templates as {{ siteName }} and {{ currentYear }}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
### `SafeString`
|
|
209
|
-
|
|
210
|
-
Class for values that should **bypass HTML auto-escaping**. Construct directly or use `markSafe()`.
|
|
211
|
-
|
|
212
|
-
**Example**:
|
|
213
|
-
```javascript
|
|
214
|
-
const { SafeString } = require('miki-template');
|
|
215
|
-
|
|
216
|
-
const html = new SafeString('<b>Bold</b>');
|
|
217
|
-
// {{ html }} renders as <b>Bold</b>, NOT <b>Bold</b>
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
### `markSafe(value)`
|
|
223
|
-
|
|
224
|
-
Wraps any value in a `SafeString`, instructing the engine to skip HTML escaping for that value.
|
|
225
|
-
|
|
226
|
-
**Parameters**:
|
|
227
|
-
- `value` (any): Value to mark as safe.
|
|
228
|
-
|
|
229
|
-
**Returns**: `SafeString`.
|
|
230
|
-
|
|
231
|
-
**Example**:
|
|
232
|
-
```javascript
|
|
233
|
-
const { markSafe } = require('miki-template');
|
|
234
|
-
|
|
235
|
-
const html = markSafe('<script>alert("xss")</script>');
|
|
236
|
-
// {{ html }} outputs the script tag literally (use with caution)
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
### `isSafe(value)`
|
|
242
|
-
|
|
243
|
-
Checks whether a value is a `SafeString` instance.
|
|
244
|
-
|
|
245
|
-
**Parameters**:
|
|
246
|
-
- `value` (any): Value to check.
|
|
247
|
-
|
|
248
|
-
**Returns**: `boolean`.
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
|
-
### `escapeHtml(str)`
|
|
253
|
-
|
|
254
|
-
Programmatically escapes HTML special characters (`<`, `>`, `&`, `"`, `'`).
|
|
255
|
-
|
|
256
|
-
**Parameters**:
|
|
257
|
-
- `str` (string): String to escape.
|
|
258
|
-
|
|
259
|
-
**Returns**: `string`.
|
|
260
|
-
|
|
261
|
-
---
|
|
262
|
-
|
|
263
|
-
### `clearCache()`
|
|
264
|
-
|
|
265
|
-
Clears the in-memory AST cache. Useful for development or when templates change at runtime.
|
|
266
|
-
|
|
267
|
-
**Example**:
|
|
268
|
-
```javascript
|
|
269
|
-
const { clearCache } = require('miki-template');
|
|
270
|
-
|
|
271
|
-
app.on('restart', () => clearCache());
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
---
|
|
275
|
-
|
|
276
|
-
## Compiled Template API
|
|
277
|
-
|
|
278
|
-
`compile()` returns an object with these methods:
|
|
279
|
-
|
|
280
|
-
### `compiled.render(context)`
|
|
281
|
-
|
|
282
|
-
Synchronously renders the template with the given context.
|
|
283
|
-
|
|
284
|
-
```javascript
|
|
285
|
-
const compiled = compile('Hello {{ name }}!');
|
|
286
|
-
compiled.render({ name: 'World' }); // "Hello World!"
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
### `compiled.asyncRender(context)`
|
|
290
|
-
|
|
291
|
-
Renders asynchronously, awaiting any Promise-returning helpers.
|
|
292
|
-
|
|
293
|
-
```javascript
|
|
294
|
-
const html = await compiled.asyncRender({ name: 'Async' });
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### `compiled.renderBlock(blockName, context)`
|
|
298
|
-
|
|
299
|
-
Renders **only** the named block. Useful for HTMX or AJAX partial responses.
|
|
300
|
-
|
|
301
|
-
```javascript
|
|
302
|
-
// Template: {% extends "base.html" %}
|
|
303
|
-
// {% block content %}Main{% endblock %}
|
|
304
|
-
compiled.renderBlock('content', {}); // "Main"
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### `compiled.renderPartial(partialName, context)`
|
|
308
|
-
|
|
309
|
-
Renders a `{% partialdef %}` block by name.
|
|
310
|
-
|
|
311
|
-
```javascript
|
|
312
|
-
// Template: {% partialdef header %}My Header{% endpartialdef %}
|
|
313
|
-
compiled.renderPartial('header', {}); // "My Header"
|
|
314
|
-
```
|
|
1
|
+
# API Reference - miki-template
|
|
2
|
+
|
|
3
|
+
This document provides complete details for the public APIs exported by the **miki-template** engine — a Django-style template engine for Node.js and Express.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Core Exports
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
const {
|
|
11
|
+
compile,
|
|
12
|
+
render,
|
|
13
|
+
asyncRender,
|
|
14
|
+
__express,
|
|
15
|
+
clearCache,
|
|
16
|
+
registerTag,
|
|
17
|
+
registerFilter,
|
|
18
|
+
registerHelper,
|
|
19
|
+
registerContextProcessor,
|
|
20
|
+
SafeString,
|
|
21
|
+
markSafe,
|
|
22
|
+
isSafe,
|
|
23
|
+
escapeHtml
|
|
24
|
+
} = require('miki-template');
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
### `compile(templateStr, options)`
|
|
30
|
+
|
|
31
|
+
Compiles a raw template string into a reusable compiled template object. The compiled template caches its AST internally.
|
|
32
|
+
|
|
33
|
+
**Parameters**:
|
|
34
|
+
- `templateStr` (string): The raw template string to compile.
|
|
35
|
+
- `options` (object): Config parameters:
|
|
36
|
+
- `views` (string|string[]): Directories to search for templates when using `extends` or `include`.
|
|
37
|
+
- `staticUrl` (string): Prefix for the `{% static %}` tag. Defaults to `/static/`.
|
|
38
|
+
- `urlHelper` (function): Custom URL resolver for `{% url %}` tag.
|
|
39
|
+
|
|
40
|
+
**Returns**: An object containing:
|
|
41
|
+
- `render(context)` — Synchronously renders the template.
|
|
42
|
+
- `asyncRender(context)` — Returns a Promise for async rendering.
|
|
43
|
+
- `renderBlock(blockName, context)` — Renders a specific block by name.
|
|
44
|
+
- `renderPartial(partialName, context)` — Renders a defined partial by name.
|
|
45
|
+
|
|
46
|
+
**Example**:
|
|
47
|
+
```javascript
|
|
48
|
+
const { compile } = require('miki-template');
|
|
49
|
+
|
|
50
|
+
const template = compile('Hello {{ name }}!');
|
|
51
|
+
const output = template.render({ name: 'World' });
|
|
52
|
+
console.log(output); // Hello World!
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### `render(templateStr, context, options)`
|
|
58
|
+
|
|
59
|
+
One-step convenience function that compiles and renders a template.
|
|
60
|
+
|
|
61
|
+
**Parameters**:
|
|
62
|
+
- `templateStr` (string): Raw template string.
|
|
63
|
+
- `context` (object): Variables available to the template.
|
|
64
|
+
- `options` (object): Same as `compile()` options.
|
|
65
|
+
|
|
66
|
+
**Returns**: Rendered HTML string.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### `asyncRender(templateStr, context, options)`
|
|
71
|
+
|
|
72
|
+
Asynchronous rendering for templates with async helpers or async context processors.
|
|
73
|
+
|
|
74
|
+
**Parameters**: Same as `render()`.
|
|
75
|
+
|
|
76
|
+
**Returns**: `Promise<string>` — resolved rendered HTML.
|
|
77
|
+
|
|
78
|
+
**Example**:
|
|
79
|
+
```javascript
|
|
80
|
+
const { asyncRender } = require('miki-template');
|
|
81
|
+
const html = await asyncRender('Hello {{ name }}!', { name: 'Async' });
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### `__express(filePath, options, callback)`
|
|
87
|
+
|
|
88
|
+
Express-compatible view engine adapter. Use with `app.engine()`.
|
|
89
|
+
|
|
90
|
+
**Parameters**:
|
|
91
|
+
- `filePath` (string): Absolute path to the template file.
|
|
92
|
+
- `options` (object): Express `res.render()` context (view engine strips `_locals`, `settings`, and other Express internals).
|
|
93
|
+
- `callback` (function): Node.js callback `(err, html)`.
|
|
94
|
+
|
|
95
|
+
**Example**:
|
|
96
|
+
```javascript
|
|
97
|
+
const express = require('express');
|
|
98
|
+
const { __express } = require('miki-template');
|
|
99
|
+
|
|
100
|
+
const app = express();
|
|
101
|
+
app.engine('html', __express);
|
|
102
|
+
app.set('view engine', 'html');
|
|
103
|
+
app.set('views', './views');
|
|
104
|
+
|
|
105
|
+
app.get('/', (req, res) => {
|
|
106
|
+
res.render('home', { title: 'Home Page' });
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### `registerTag(name, parserFn)`
|
|
113
|
+
|
|
114
|
+
Registers a custom block tag parser. Must be called **before** compiling templates that use the tag.
|
|
115
|
+
|
|
116
|
+
**Parameters**:
|
|
117
|
+
- `name` (string): Tag identifier word (e.g. `mytag` for `{% mytag %}`).
|
|
118
|
+
- `parserFn` (function): `(tagContent: string, parser: Parser) => ASTNode`. Receives the raw tag content and the parser instance.
|
|
119
|
+
|
|
120
|
+
**Returns**: `undefined`.
|
|
121
|
+
|
|
122
|
+
**Example**:
|
|
123
|
+
```javascript
|
|
124
|
+
const { registerTag } = require('miki-template');
|
|
125
|
+
|
|
126
|
+
registerTag('greet', (tagContent, parser) => {
|
|
127
|
+
const name = tagContent.slice(5).trim(); // strip 'greet'
|
|
128
|
+
return {
|
|
129
|
+
render: (context) => `Hello ${context.get(name) || 'Guest'}!`
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// In template: {% greet user.name %}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### `registerFilter(name, filterFn)`
|
|
139
|
+
|
|
140
|
+
Registers a custom filter function.
|
|
141
|
+
|
|
142
|
+
**Parameters**:
|
|
143
|
+
- `name` (string): Filter name used after the pipe `|`.
|
|
144
|
+
- `filterFn` (function): `(value: any, arg?: any) => any`. Receives the filtered value and optional argument.
|
|
145
|
+
|
|
146
|
+
**Returns**: `undefined`.
|
|
147
|
+
|
|
148
|
+
**Example**:
|
|
149
|
+
```javascript
|
|
150
|
+
const { registerFilter } = require('miki-template');
|
|
151
|
+
|
|
152
|
+
registerFilter('reverse', (val) => {
|
|
153
|
+
return String(val).split('').reverse().join('');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// In template: {{ name|reverse }}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### `registerHelper(name, fn)`
|
|
162
|
+
|
|
163
|
+
Registers a custom block helper tag. The helper receives the **rendered** inner content as a string.
|
|
164
|
+
|
|
165
|
+
**Parameters**:
|
|
166
|
+
- `name` (string): Tag name (e.g. `markdown` creates `{% markdown %}...{% endmarkdown %}`).
|
|
167
|
+
- `fn` (function): `(innerContent: string, context: Context) => string | Promise<string>`.
|
|
168
|
+
|
|
169
|
+
**Returns**: `undefined`.
|
|
170
|
+
|
|
171
|
+
**Example**:
|
|
172
|
+
```javascript
|
|
173
|
+
const { registerHelper } = require('miki-template');
|
|
174
|
+
const markdownIt = require('markdown-it')();
|
|
175
|
+
registerHelper('markdown', (content) => markdownIt.render(content));
|
|
176
|
+
|
|
177
|
+
// In template:
|
|
178
|
+
// {% markdown %}
|
|
179
|
+
// # Hello
|
|
180
|
+
// {% endmarkdown %}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### `registerContextProcessor(fn)`
|
|
186
|
+
|
|
187
|
+
Adds a context processor function. Similar to Django's custom context processors.
|
|
188
|
+
|
|
189
|
+
**Parameters**:
|
|
190
|
+
- `fn` (function): `(context: object) => object | undefined`. Receives the render context and returns extra key-value pairs to merge in.
|
|
191
|
+
|
|
192
|
+
**Returns**: `undefined`.
|
|
193
|
+
|
|
194
|
+
**Example**:
|
|
195
|
+
```javascript
|
|
196
|
+
const { registerContextProcessor } = require('miki-template');
|
|
197
|
+
|
|
198
|
+
registerContextProcessor((ctx) => ({
|
|
199
|
+
siteName: 'MySite',
|
|
200
|
+
currentYear: new Date().getFullYear()
|
|
201
|
+
}));
|
|
202
|
+
|
|
203
|
+
// Available in all templates as {{ siteName }} and {{ currentYear }}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
### `SafeString`
|
|
209
|
+
|
|
210
|
+
Class for values that should **bypass HTML auto-escaping**. Construct directly or use `markSafe()`.
|
|
211
|
+
|
|
212
|
+
**Example**:
|
|
213
|
+
```javascript
|
|
214
|
+
const { SafeString } = require('miki-template');
|
|
215
|
+
|
|
216
|
+
const html = new SafeString('<b>Bold</b>');
|
|
217
|
+
// {{ html }} renders as <b>Bold</b>, NOT <b>Bold</b>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### `markSafe(value)`
|
|
223
|
+
|
|
224
|
+
Wraps any value in a `SafeString`, instructing the engine to skip HTML escaping for that value.
|
|
225
|
+
|
|
226
|
+
**Parameters**:
|
|
227
|
+
- `value` (any): Value to mark as safe.
|
|
228
|
+
|
|
229
|
+
**Returns**: `SafeString`.
|
|
230
|
+
|
|
231
|
+
**Example**:
|
|
232
|
+
```javascript
|
|
233
|
+
const { markSafe } = require('miki-template');
|
|
234
|
+
|
|
235
|
+
const html = markSafe('<script>alert("xss")</script>');
|
|
236
|
+
// {{ html }} outputs the script tag literally (use with caution)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### `isSafe(value)`
|
|
242
|
+
|
|
243
|
+
Checks whether a value is a `SafeString` instance.
|
|
244
|
+
|
|
245
|
+
**Parameters**:
|
|
246
|
+
- `value` (any): Value to check.
|
|
247
|
+
|
|
248
|
+
**Returns**: `boolean`.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### `escapeHtml(str)`
|
|
253
|
+
|
|
254
|
+
Programmatically escapes HTML special characters (`<`, `>`, `&`, `"`, `'`).
|
|
255
|
+
|
|
256
|
+
**Parameters**:
|
|
257
|
+
- `str` (string): String to escape.
|
|
258
|
+
|
|
259
|
+
**Returns**: `string`.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### `clearCache()`
|
|
264
|
+
|
|
265
|
+
Clears the in-memory AST cache. Useful for development or when templates change at runtime.
|
|
266
|
+
|
|
267
|
+
**Example**:
|
|
268
|
+
```javascript
|
|
269
|
+
const { clearCache } = require('miki-template');
|
|
270
|
+
|
|
271
|
+
app.on('restart', () => clearCache());
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Compiled Template API
|
|
277
|
+
|
|
278
|
+
`compile()` returns an object with these methods:
|
|
279
|
+
|
|
280
|
+
### `compiled.render(context)`
|
|
281
|
+
|
|
282
|
+
Synchronously renders the template with the given context.
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
285
|
+
const compiled = compile('Hello {{ name }}!');
|
|
286
|
+
compiled.render({ name: 'World' }); // "Hello World!"
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### `compiled.asyncRender(context)`
|
|
290
|
+
|
|
291
|
+
Renders asynchronously, awaiting any Promise-returning helpers.
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
const html = await compiled.asyncRender({ name: 'Async' });
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### `compiled.renderBlock(blockName, context)`
|
|
298
|
+
|
|
299
|
+
Renders **only** the named block. Useful for HTMX or AJAX partial responses.
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
// Template: {% extends "base.html" %}
|
|
303
|
+
// {% block content %}Main{% endblock %}
|
|
304
|
+
compiled.renderBlock('content', {}); // "Main"
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### `compiled.renderPartial(partialName, context)`
|
|
308
|
+
|
|
309
|
+
Renders a `{% partialdef %}` block by name.
|
|
310
|
+
|
|
311
|
+
```javascript
|
|
312
|
+
// Template: {% partialdef header %}My Header{% endpartialdef %}
|
|
313
|
+
compiled.renderPartial('header', {}); // "My Header"
|
|
314
|
+
```
|