miki-template 2.2.3 → 2.3.1

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 (66) hide show
  1. package/.github/workflows/docs.yml +3 -1
  2. package/.github/workflows/release.yml +0 -5
  3. package/README.md +17 -5
  4. package/benchmarks/ejs-results.json +6 -6
  5. package/benchmarks/ejs.js +5 -3
  6. package/benchmarks/handlebars-results.json +6 -6
  7. package/benchmarks/handlebars.js +5 -8
  8. package/benchmarks/miki-results.json +6 -6
  9. package/benchmarks/miki.js +6 -3
  10. package/benchmarks/pug-results.json +6 -6
  11. package/benchmarks/pug.js +5 -3
  12. package/docs/api/async-render.md +88 -3
  13. package/docs/api/cache.md +90 -3
  14. package/docs/api/compile.md +131 -3
  15. package/docs/api/context-processors.md +80 -3
  16. package/docs/api/filters.md +223 -3
  17. package/docs/api/finder.md +97 -3
  18. package/docs/api/helpers.md +56 -3
  19. package/docs/api/i18n.md +160 -3
  20. package/docs/api/index.md +82 -28
  21. package/docs/api/libraries.md +210 -3
  22. package/docs/api/render-partial.md +84 -3
  23. package/docs/api/render.md +95 -3
  24. package/docs/api/security.md +148 -3
  25. package/docs/api/setup-express.md +78 -2
  26. package/docs/api/tags.md +138 -4
  27. package/docs/filter.md +0 -0
  28. package/docs/guide/advanced-usage.md +403 -6
  29. package/docs/guide/async-rendering.md +312 -4
  30. package/docs/guide/context-processors.md +261 -4
  31. package/docs/guide/custom-filters.md +315 -4
  32. package/docs/guide/custom-tags.md +275 -4
  33. package/docs/guide/filters.md +675 -3
  34. package/docs/guide/getting-started.md +109 -7
  35. package/docs/guide/installation.md +99 -4
  36. package/docs/guide/partial-templates.md +371 -4
  37. package/docs/guide/quick-start.md +228 -6
  38. package/docs/guide/security.md +348 -3
  39. package/docs/guide/tags.md +789 -6
  40. package/docs/guide/template-discovery.md +174 -4
  41. package/docs/guide/template-inheritance.md +277 -4
  42. package/docs/index.md +24 -42
  43. package/docs/integrations/elysia.md +4 -2
  44. package/docs/integrations/express.md +219 -219
  45. package/docs/integrations/fastify.md +4 -2
  46. package/docs/integrations/hono.md +4 -2
  47. package/docs/integrations/index.md +68 -68
  48. package/docs/integrations/koa.md +4 -2
  49. package/docs/integrations/nestjs.md +4 -2
  50. package/docs/integrations/tsed.md +4 -2
  51. package/docs/performance.md +45 -8
  52. package/ex.mjs +1 -1
  53. package/mkdocs.yml +0 -22
  54. package/overrides/main.html +1 -1
  55. package/package.json +1 -1
  56. package/requirements-docs.txt +2 -1
  57. package/src/codegen.js +905 -0
  58. package/src/context.js +42 -30
  59. package/src/filters.js +16 -0
  60. package/src/index.js +66 -61
  61. package/src/tags/control.js +15 -12
  62. package/src/utils.js +60 -0
  63. package/tests/filters.test.js +9 -0
  64. package/docs/javascripts/extra.js +0 -174
  65. package/docs/stylesheets/extra.css +0 -819
  66. package/overrides/partials/footer.html +0 -9
@@ -1,273 +1,546 @@
1
- # Template Inheritance
1
+ # Template Inheritance
2
+
3
+
2
4
 
3
5
  miki-template supports Django-style template inheritance via `{% extends %}` and `{% block %}`. This lets you build layout hierarchies where child templates override parent blocks.
4
6
 
7
+
8
+
5
9
  ## Table of Contents
6
10
 
11
+
12
+
7
13
  - [Basic Inheritance](#basic-inheritance)
14
+
8
15
  - [block.super](#blocksuper)
16
+
9
17
  - [Multi-Level Inheritance](#multi-level-inheritance)
18
+
10
19
  - [Rendering a Single Block](#rendering-a-single-block)
20
+
11
21
  - [block Default Behavior](#block-default-behavior)
22
+
12
23
  - [Path Traversal Protection](#path-traversal-protection)
24
+
13
25
  - [Smart Template Discovery for Inheritance](#smart-template-discovery-for-inheritance)
14
26
 
27
+
28
+
15
29
  ---
16
30
 
31
+
32
+
17
33
  ## Basic Inheritance
18
34
 
35
+
36
+
19
37
  ### base.html
20
38
 
39
+
40
+
21
41
  ```html
42
+
22
43
  <!DOCTYPE html>
44
+
23
45
  <html>
46
+
24
47
  <head>
48
+
25
49
  <title>{% block title %}Default Title{% endblock %}</title>
50
+
26
51
  </head>
52
+
27
53
  <body>
54
+
28
55
  <header>{% block header %}Default Header{% endblock %}</header>
56
+
29
57
  <main>{% block content %}Default Content{% endblock %}</main>
58
+
30
59
  <footer>{% block footer %}Default Footer{% endblock %}</footer>
60
+
31
61
  </body>
62
+
32
63
  </html>
64
+
33
65
  ```
34
66
 
67
+
68
+
35
69
  ### child.html
36
70
 
71
+
72
+
37
73
  ```html
74
+
38
75
  {% extends "base.html" %}
39
76
 
77
+
78
+
40
79
  {% block title %}My Page{% endblock %}
41
80
 
81
+
82
+
42
83
  {% block content %}
84
+
43
85
  <h1>Hello, {{ user.name }}!</h1>
86
+
44
87
  {% for item in items %}
88
+
45
89
  <p>{{ item }}</p>
90
+
46
91
  {% endfor %}
92
+
47
93
  {% endblock %}
94
+
48
95
  ```
49
96
 
97
+
98
+
50
99
  **Key behaviors:**
51
100
 
101
+
102
+
52
103
  - The child template's text outside `{% block %}` tags is **ignored** — only the blocks are used to override the parent.
104
+
53
105
  - Any blocks not overridden in the child use the parent's default content.
106
+
54
107
  - The parent is located using the `views` option (or Express's `views` directory).
55
108
 
109
+
110
+
56
111
  ## block.super
57
112
 
113
+
114
+
58
115
  Inside a block, `{{ block.super }}` renders the parent template's version of that block. This is useful for augmentation rather than replacement.
59
116
 
117
+
118
+
60
119
  === "Example"
61
120
 
121
+
122
+
62
123
  ```html
124
+
63
125
  {% extends "base.html" %}
64
126
 
127
+
128
+
65
129
  {% block content %}
130
+
66
131
  <h1>My Content</h1>
132
+
67
133
  {{ block.super }}
134
+
68
135
  {% endblock %}
136
+
69
137
  ```
70
138
 
139
+
140
+
71
141
  If `base.html`'s content block is `<p>Original</p>`, the output is:
72
142
 
143
+
144
+
73
145
  ```html
146
+
74
147
  <h1>My Content</h1>
148
+
75
149
  <p>Original</p>
150
+
76
151
  ```
77
152
 
153
+
154
+
78
155
  **Real-world sidebar that adds to the parent:**
79
156
 
157
+
158
+
80
159
  ```html
160
+
81
161
  <!-- base.html -->
162
+
82
163
  {% block sidebar %}
164
+
83
165
  <ul class="nav">
166
+
84
167
  <li><a href="/">Home</a></li>
168
+
85
169
  </ul>
170
+
86
171
  {% endblock %}
87
172
 
173
+
174
+
88
175
  <!-- admin.html -->
176
+
89
177
  {% extends "base.html" %}
178
+
90
179
  {% block sidebar %}
180
+
91
181
  {{ block.super }}
182
+
92
183
  <li><a href="/admin">Admin Panel</a></li>
184
+
93
185
  {% endblock %}
186
+
94
187
  ```
95
188
 
189
+
190
+
96
191
  ## Multi-Level Inheritance
97
192
 
193
+
194
+
98
195
  Inheritance chains can be arbitrarily deep:
99
196
 
197
+
198
+
100
199
  ```text
200
+
101
201
  base.html
202
+
102
203
  └── child.html
204
+
103
205
  └── grandchild.html
206
+
104
207
  ```
105
208
 
209
+
210
+
106
211
  Each level can override blocks from its parent, and `{{ block.super }}` traverses the chain correctly.
107
212
 
213
+
214
+
108
215
  ### Three-level example
109
216
 
217
+
218
+
110
219
  **base.html:**
111
220
 
221
+
222
+
112
223
  ```html
224
+
113
225
  <html>
226
+
114
227
  <body>
228
+
115
229
  {% block content %}Base content{% endblock %}
230
+
116
231
  </body>
232
+
117
233
  </html>
234
+
118
235
  ```
119
236
 
237
+
238
+
120
239
  **child.html:**
121
240
 
241
+
242
+
122
243
  ```html
244
+
123
245
  {% extends "base.html" %}
124
246
 
247
+
248
+
125
249
  {% block content %}
250
+
126
251
  <h2>Child content</h2>
252
+
127
253
  {{ block.super }}
254
+
128
255
  {% endblock %}
256
+
129
257
  ```
130
258
 
259
+
260
+
131
261
  **grandchild.html:**
132
262
 
263
+
264
+
133
265
  ```html
266
+
134
267
  {% extends "child.html" %}
135
268
 
269
+
270
+
136
271
  {% block content %}
272
+
137
273
  <h1>Grandchild content</h1>
274
+
138
275
  {{ block.super }}
276
+
139
277
  {% endblock %}
278
+
140
279
  ```
141
280
 
281
+
282
+
142
283
  Rendering `grandchild.html` produces:
143
284
 
285
+
286
+
144
287
  ```html
288
+
145
289
  <html>
290
+
146
291
  <body>
292
+
147
293
  <h1>Grandchild content</h1>
294
+
148
295
  <h2>Child content</h2>
296
+
149
297
  Base content
298
+
150
299
  </body>
300
+
151
301
  </html>
302
+
152
303
  ```
153
304
 
305
+
306
+
154
307
  ## Rendering a Single Block
155
308
 
309
+
310
+
156
311
  Compile a template and render only one block — useful for AJAX or HTMX responses where you only need a portion of the page:
157
312
 
313
+
314
+
158
315
  === "CommonJS"
159
316
 
317
+
318
+
160
319
  ```javascript
320
+
161
321
  const { compile } = require('miki-template');
162
322
 
323
+
324
+
163
325
  const compiled = compile(childTemplateStr, { views: './templates' });
326
+
164
327
  const partialHtml = compiled.renderBlock('content', context);
328
+
165
329
  ```
166
330
 
331
+
332
+
167
333
  === "ES Modules"
168
334
 
335
+
336
+
169
337
  ```javascript
338
+
170
339
  import { compile } from 'miki-template';
171
340
 
341
+
342
+
172
343
  const compiled = compile(childTemplateStr, { views: './templates' });
344
+
173
345
  const partialHtml = compiled.renderBlock('content', context);
346
+
174
347
  ```
175
348
 
349
+
350
+
176
351
  ### renderBlock behavior
177
352
 
353
+
354
+
178
355
  - If the block is not found, throws `Block 'blockName' not found in template`.
356
+
179
357
  - If the block has no overrides, renders the default body.
358
+
180
359
  - If the block has overrides, renders the child-most block first, then traverses up for `{{ block.super }}`.
181
360
 
361
+
362
+
182
363
  **Real-world HTMX use case:**
183
364
 
365
+
366
+
184
367
  ```html
368
+
185
369
  <!-- layout.html -->
370
+
186
371
  {% block main %}
372
+
187
373
  <div id="main-content">
374
+
188
375
  <!-- default content -->
376
+
189
377
  </div>
378
+
190
379
  {% endblock %}
380
+
191
381
  ```
192
382
 
383
+
384
+
193
385
  ```javascript
386
+
194
387
  // Return only the main block for an AJAX update
388
+
195
389
  app.get('/ajax/content', (req, res) => {
390
+
196
391
  const compiled = miki.compile(template, { views: './views' });
392
+
197
393
  res.send(compiled.renderBlock('main', { user: req.user }));
394
+
198
395
  });
396
+
199
397
  ```
200
398
 
399
+
400
+
201
401
  ## block Default Behavior
202
402
 
403
+
404
+
203
405
  If a child template does not override a block, the parent's default content is rendered:
204
406
 
407
+
408
+
205
409
  ```html
410
+
206
411
  <!-- base.html -->
412
+
207
413
  <html>
414
+
208
415
  <body>
416
+
209
417
  {% block sidebar %}Default sidebar{% endblock %}
418
+
210
419
  </body>
420
+
211
421
  </html>
422
+
212
423
  ```
213
424
 
425
+
426
+
214
427
  ```html
428
+
215
429
  <!-- child.html -->
430
+
216
431
  {% extends "base.html" %}
217
432
 
433
+
434
+
218
435
  {% block content %}Main content{% endblock %}
436
+
219
437
  <!-- sidebar block is not overridden, so "Default sidebar" is used -->
438
+
220
439
  ```
221
440
 
441
+
442
+
222
443
  ## Dynamic extends
223
444
 
445
+
446
+
224
447
  You can use expressions in `extends` for device-specific or conditional layouts:
225
448
 
449
+
450
+
226
451
  ```html
452
+
227
453
  {% extends device_type|default:"base.html" %}
454
+
228
455
  ```
229
456
 
457
+
458
+
230
459
  ```html
460
+
231
461
  {% extends user.theme|default:"default.html" %}
462
+
232
463
  ```
233
464
 
465
+
466
+
234
467
  ## Path Traversal Protection
235
468
 
469
+
470
+
236
471
  `{% extends %}` and `{% include %}` paths are validated to prevent directory traversal attacks:
237
472
 
473
+
474
+
238
475
  ```html
476
+
239
477
  {% extends "../../etc/passwd" %} {# REJECTED #}
478
+
240
479
  {% include "../../secrets" %} {# REJECTED #}
480
+
241
481
  ```
242
482
 
483
+
484
+
243
485
  The engine checks that resolved paths stay within the allowed views directories. An `Error` with message starting `path traversal` is thrown if a path escapes the views root.
244
486
 
487
+
488
+
245
489
  ## Smart Template Discovery for Inheritance
246
490
 
491
+
492
+
247
493
  When using `setupExpress()`, the engine automatically searches for parent templates in:
248
494
 
495
+
496
+
249
497
  - The configured `views` directory
498
+
250
499
  - Nested `templates/` directories inside the views root
500
+
251
501
  - Subdirectories of the views root
502
+
252
503
  - App-style `app/templates/...`, `packages/*/templates/...`, etc.
253
504
 
505
+
506
+
254
507
  This means you can organize templates like:
255
508
 
509
+
510
+
256
511
  ```text
512
+
257
513
  project/
514
+
258
515
  ├── views/
516
+
259
517
  │ ├── base.html
518
+
260
519
  │ └── home.html
520
+
261
521
  ├── app/
522
+
262
523
  │ └── templates/
524
+
263
525
  │ └── admin/
526
+
264
527
  │ └── dashboard.html
528
+
265
529
  ```
266
530
 
531
+
532
+
267
533
  And `{% extends "base.html" %}` will be found regardless of where the child template lives.
268
534
 
535
+
536
+
269
537
  ## Next Steps
270
538
 
271
- - [Partial Templates](./partial-templates)
272
- - [Tags: extends and block](./tags#inheritance-tags)
273
- - [Template Discovery](./template-discovery)
539
+
540
+
541
+ - [Partial Templates](./partial-templates.md)
542
+
543
+ - [Tags: extends and block](./tags.md#inheritance-tags)
544
+
545
+ - [Template Discovery](./template-discovery.md)
546
+
package/docs/index.md CHANGED
@@ -1,30 +1,14 @@
1
- <div class="md-hero">
2
- <h1 class="md-hero__title">miki-template</h1>
3
- <p class="md-hero__subtitle">Django-style template magic for Node.js — blazing fast partials, smart template discovery, and zero friction for HTMX.</p>
4
- <div class="md-hero__buttons">
5
- <a href="guide/quick-start" class="md-button md-button--primary">Get Started</a>
6
- <a href="api/" class="md-button">API Reference</a>
7
- <a href="https://github.com/alainmiki/miki-template" class="md-button" target="_blank" rel="noopener">
8
- <span class="md-icon">&#128190;</span> GitHub
9
- </a>
10
- </div>
11
- <div style="margin-top: 1.5rem; display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; position: relative; align-items: center;">
12
- <img src="assets/banner.png" alt="miki-template banner" style="max-width: 100%; height: auto; border-radius: 0.5rem; box-shadow: 0 4px 12px var(--md-shadow-color); max-height: 200px;">
13
- </div>
14
- <div style="margin-top: 1rem; display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; position: relative; align-items: center;">
15
- <a href="https://www.npmjs.com/package/miki-template" target="_blank" rel="noopener">
16
- <img src="https://img.shields.io/npm/v/miki-template.svg" alt="npm version" style="height: 20px;">
17
- </a>
18
- <a href="https://www.npmjs.com/package/miki-template" target="_blank" rel="noopener">
19
- <img src="https://img.shields.io/npm/dm/miki-template.svg" alt="npm downloads" style="height: 20px;">
20
- </a>
21
- <a href="https://github.com/alainmiki/miki-template" target="_blank" rel="noopener">
22
- <img src="https://img.shields.io/github/actions/workflow/status/alainmiki/miki-template/ci.yml?branch=main" alt="CI status" style="height: 20px;">
23
- </a>
24
- </div>
25
- </div>
26
-
27
- <div class="md-typeset">
1
+ # miki-template
2
+
3
+ Django-style template magic for Node.js — blazing fast partials, smart template discovery, and zero friction for HTMX.
4
+ miki comes with more tags and filters that are not in django/jinja and miki templates supports all django tags and filters plus it own additional tags and filters.
5
+ you can register your own custom filters and filters in miki templates.
6
+
7
+ miki is secure and production ready with active maintainer and performance improvements.
8
+
9
+ [Get Started](guide/quick-start.md) | [API Reference](api/index.md) | [GitHub](https://github.com/alainmiki/miki-template)
10
+
11
+ ![miki-template banner](assets/banner.png)
28
12
 
29
13
  ## Why miki-template?
30
14
 
@@ -80,25 +64,23 @@ miki-template brings Django's beloved template language to Node.js and Express.
80
64
  npm install miki-template
81
65
  ```
82
66
 
83
- See the [Installation guide](guide/installation) for pnpm, yarn, and Bun instructions.
67
+ See the [Installation guide](guide/installation.md) for pnpm, yarn, and Bun instructions.
84
68
 
85
69
  ## Documentation
86
70
 
87
- - [What is miki-template?](guide/what-is-miki-template)
88
- - [Getting Started](guide/getting-started)
89
- - [Quick Start](guide/quick-start)
90
- - [Filters](guide/filters)
91
- - [Tags](guide/tags)
92
- - [Partial Templates](guide/partial-templates)
93
- - [Template Inheritance](guide/template-inheritance)
94
- - [Template Discovery](guide/template-discovery)
95
- - [Security](guide/security)
96
- - [Integrations](integrations/)
97
- - [API Reference](api/)
98
- - [Performance](performance)
71
+ - [What is miki-template?](guide/what-is-miki-template.md)
72
+ - [Getting Started](guide/getting-started.md)
73
+ - [Quick Start](guide/quick-start.md)
74
+ - [Filters](guide/filters.md)
75
+ - [Tags](guide/tags.md)
76
+ - [Partial Templates](guide/partial-templates.md)
77
+ - [Template Inheritance](guide/template-inheritance.md)
78
+ - [Template Discovery](guide/template-discovery.md)
79
+ - [Security](guide/security.md)
80
+ - [Integrations](integrations/index.md)
81
+ - [API Reference](api/index.md)
82
+ - [Performance](performance.md)
99
83
 
100
84
  ## License
101
85
 
102
86
  MIT
103
-
104
- </div>
@@ -74,5 +74,7 @@ Use miki-template with Elysia (Bun-native framework) by calling `asyncRender()`
74
74
 
75
75
  ## Next Steps
76
76
 
77
- - [Integrations Overview](../)
78
- - [API Reference: asyncRender](../api/async-render)
77
+ - [Integrations Overview](../index.md)
78
+ - [API Reference: asyncRender param($m) $m.Value -replace '([a-z][a-z0-9-]+)\.md
79
+ , '../.md' -replace '([a-z][a-z0-9-]+)
80
+ , '../.md'