miki-template 1.2.0 → 1.3.6

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.
Files changed (105) hide show
  1. package/.github/release-notes/v1.3.1.md +55 -0
  2. package/.github/release-notes/v1.3.3.md +77 -0
  3. package/.github/workflows/ci.yml +38 -54
  4. package/.github/workflows/release.yml +106 -0
  5. package/AGENT.md +71 -71
  6. package/API_REFERENCE.md +314 -314
  7. package/CHANGELOG.md +173 -97
  8. package/CODE_OF_CONDUCT.md +14 -14
  9. package/CONTRIBUTING.md +27 -27
  10. package/README.md +342 -304
  11. package/ROADMAP.md +40 -40
  12. package/assets/banner.png +0 -0
  13. package/benchmarks/report.json +16 -16
  14. package/benchmarks/run.js +49 -49
  15. package/benchmarks/stress.mjs +647 -0
  16. package/benchmarks/templates/large.dtpl +7 -7
  17. package/benchmarks/templates/medium.dtpl +3 -3
  18. package/benchmarks/templates/small.dtpl +7 -7
  19. package/context/component.md +109 -109
  20. package/context/prd.md +131 -131
  21. package/context/project-structure.md +33 -33
  22. package/dir/base.html +23 -0
  23. package/dir/cmpnt.html +11 -0
  24. package/dir/footer.html +3 -0
  25. package/dir/home.html +80 -0
  26. package/dir/index.html +80 -0
  27. package/dir/navbar.html +9 -0
  28. package/docs/README.md +18 -18
  29. package/docs/advanced_usage.md +71 -71
  30. package/docs/api.md +119 -102
  31. package/docs/filters.md +708 -540
  32. package/docs/installation.md +106 -106
  33. package/docs/overview.md +57 -57
  34. package/docs/partialdef.md +70 -41
  35. package/docs/security.md +27 -27
  36. package/docs/tags.md +673 -610
  37. package/docs/usage.md +646 -599
  38. package/eslint.config.mjs +42 -34
  39. package/ex.mjs +33 -0
  40. package/miki-template-extension/.github/workflows/ci.yml +116 -0
  41. package/miki-template-extension/.vscodeignore +7 -0
  42. package/miki-template-extension/CHANGELOG.md +99 -0
  43. package/miki-template-extension/LICENSE +21 -21
  44. package/miki-template-extension/README.md +273 -82
  45. package/miki-template-extension/extension.js +1013 -0
  46. package/miki-template-extension/icon.png +0 -0
  47. package/miki-template-extension/icon.svg +10 -10
  48. package/miki-template-extension/miki-template-1.7.1.vsix +0 -0
  49. package/miki-template-extension/package.json +280 -46
  50. package/miki-template-extension/snippets/miki-template.json +717 -177
  51. package/miki-template-extension/syntaxes/language-configuration.json +114 -26
  52. package/miki-template-extension/syntaxes/miki-template.tmLanguage.json +355 -146
  53. package/miki-template-extension/tests/grammar-tests.json +162 -0
  54. package/miki-template-extension/tests/run-grammar-tests.js +82 -0
  55. package/package.json +37 -31
  56. package/sample-app/package-lock.json +901 -0
  57. package/sample-app/package.json +9 -0
  58. package/sample-app/server.js +14 -0
  59. package/sample-app/views/index.html +1 -0
  60. package/scripts/build-vsix.js +129 -0
  61. package/scripts/build-vsix.ps1 +15 -0
  62. package/snippets/miki-template.json +177 -177
  63. package/src/asyncRender.js +20 -20
  64. package/src/cache.js +80 -41
  65. package/src/context.js +126 -122
  66. package/src/context_processors.js +48 -41
  67. package/src/esm.mjs +84 -72
  68. package/src/filters.js +975 -527
  69. package/src/i18n.js +171 -171
  70. package/src/index.js +974 -454
  71. package/src/lexer.js +114 -92
  72. package/src/libraries.js +371 -240
  73. package/src/parser.js +270 -250
  74. package/src/security.js +53 -51
  75. package/src/tags/control.js +719 -590
  76. package/src/tags/extra.js +154 -0
  77. package/src/tags/helpers.js +26 -26
  78. package/src/tags/i18n.js +256 -230
  79. package/src/tags/inheritance.js +335 -216
  80. package/src/tags/registry.js +18 -18
  81. package/src/tags/util.js +400 -322
  82. package/src/types.d.ts +107 -107
  83. package/syntaxes/language-configuration.json +26 -26
  84. package/syntaxes/miki-template.tmLanguage.json +146 -146
  85. package/tests/asyncRender.test.js +17 -17
  86. package/tests/base.html +6 -6
  87. package/tests/child.html +3 -3
  88. package/tests/context_processors.test.js +13 -13
  89. package/tests/esm.test.mjs +61 -26
  90. package/tests/filters.test.js +254 -99
  91. package/tests/include_security.test.js +9 -9
  92. package/tests/integration/README.md +32 -0
  93. package/tests/integration/features.test.cjs +1681 -0
  94. package/tests/integration/features.test.mjs +1697 -0
  95. package/tests/integration/templates/base.miki +6 -0
  96. package/tests/integration/templates/child.miki +6 -0
  97. package/tests/integration/templates/index.html +17 -0
  98. package/tests/lexer.test.js +45 -45
  99. package/tests/parser.test.js +57 -55
  100. package/tests/partial.html +1 -1
  101. package/tests/partialdef.test.js +79 -40
  102. package/tests/production_checks.js +57 -57
  103. package/tests/security.test.js +28 -28
  104. package/tests/tags.test.js +233 -203
  105. package/miki-template-1.2.0.vsix +0 -0
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 &lt;b&gt;Bold&lt;/b&gt;
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 &lt;b&gt;Bold&lt;/b&gt;
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
+ ```