miki-template 2.0.1 → 2.2.3

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 (71) hide show
  1. package/.github/workflows/ci.yml +13 -37
  2. package/.github/workflows/docs.yml +105 -0
  3. package/.github/workflows/release.yml +6 -0
  4. package/README.md +69 -14
  5. package/assets/logo.png +0 -0
  6. package/benchmarks/ejs-results.json +4 -4
  7. package/benchmarks/handlebars-results.json +6 -6
  8. package/benchmarks/miki-results.json +4 -4
  9. package/benchmarks/pug-results.json +4 -4
  10. package/benchmarks/stress.mjs +1 -1
  11. package/docs/api/async-render.md +85 -0
  12. package/docs/api/cache.md +87 -0
  13. package/docs/api/compile.md +128 -0
  14. package/docs/api/context-processors.md +77 -0
  15. package/docs/api/filters.md +217 -0
  16. package/docs/api/finder.md +94 -0
  17. package/docs/api/helpers.md +53 -0
  18. package/docs/api/i18n.md +157 -0
  19. package/docs/api/index.md +54 -0
  20. package/docs/api/libraries.md +207 -0
  21. package/docs/api/render-partial.md +81 -0
  22. package/docs/api/render.md +92 -0
  23. package/docs/api/security.md +145 -0
  24. package/docs/api/setup-express.md +76 -0
  25. package/docs/api/tags.md +134 -0
  26. package/docs/assets/banner.png +0 -0
  27. package/docs/assets/logo.png +0 -0
  28. package/docs/guide/advanced-usage.md +397 -0
  29. package/docs/guide/async-rendering.md +308 -0
  30. package/docs/guide/context-processors.md +257 -0
  31. package/docs/guide/custom-filters.md +311 -0
  32. package/docs/guide/custom-tags.md +271 -0
  33. package/docs/guide/filters.md +642 -0
  34. package/docs/guide/getting-started.md +102 -0
  35. package/docs/guide/installation.md +95 -0
  36. package/docs/guide/partial-templates.md +367 -0
  37. package/docs/guide/quick-start.md +222 -0
  38. package/docs/guide/security.md +345 -0
  39. package/docs/guide/tags.md +783 -0
  40. package/docs/guide/template-discovery.md +170 -0
  41. package/docs/guide/template-inheritance.md +273 -0
  42. package/docs/guide/what-is-miki-template.md +28 -0
  43. package/docs/guide/why-miki-template.md +75 -0
  44. package/docs/index.md +104 -0
  45. package/docs/integrations/elysia.md +78 -0
  46. package/docs/integrations/express.md +219 -0
  47. package/docs/integrations/fastify.md +77 -0
  48. package/docs/integrations/hono.md +78 -0
  49. package/docs/integrations/index.md +68 -0
  50. package/docs/integrations/koa.md +88 -0
  51. package/docs/integrations/nestjs.md +78 -0
  52. package/docs/integrations/tsed.md +81 -0
  53. package/docs/javascripts/extra.js +174 -0
  54. package/docs/performance.md +37 -0
  55. package/docs/stylesheets/extra.css +819 -0
  56. package/mkdocs.yml +217 -0
  57. package/overrides/main.html +26 -0
  58. package/overrides/partials/footer.html +9 -0
  59. package/package.json +4 -2
  60. package/requirements-docs.txt +1 -0
  61. package/docs/README.md +0 -18
  62. package/docs/advanced_usage.md +0 -71
  63. package/docs/api.md +0 -122
  64. package/docs/filters.md +0 -708
  65. package/docs/installation.md +0 -106
  66. package/docs/integrations.md +0 -214
  67. package/docs/overview.md +0 -79
  68. package/docs/partialdef.md +0 -70
  69. package/docs/security.md +0 -27
  70. package/docs/tags.md +0 -673
  71. package/docs/usage.md +0 -646
@@ -0,0 +1,145 @@
1
+ # Security API
2
+
3
+ ## markSafe
4
+
5
+ Mark a string as safe (bypass auto-escaping).
6
+
7
+ === "CommonJS"
8
+
9
+ ```javascript
10
+ const { markSafe } = require('miki-template');
11
+
12
+ const html = markSafe('<b>ok</b>');
13
+ // Will not be escaped
14
+ ```
15
+
16
+ === "ES Modules"
17
+
18
+ ```javascript
19
+ import { markSafe } from 'miki-template';
20
+
21
+ const html = markSafe('<b>ok</b>');
22
+ ```
23
+
24
+ ## isSafe
25
+
26
+ Check if a value is marked safe.
27
+
28
+ === "CommonJS"
29
+
30
+ ```javascript
31
+ const { isSafe } = require('miki-template');
32
+
33
+ if (isSafe(value)) {
34
+ // value is marked safe
35
+ }
36
+ ```
37
+
38
+ === "ES Modules"
39
+
40
+ ```javascript
41
+ import { isSafe } from 'miki-template';
42
+
43
+ if (isSafe(value)) {
44
+ // value is marked safe
45
+ }
46
+ ```
47
+
48
+ ## escapeHtml
49
+
50
+ Escape HTML special characters (`&`, `<`, `>`, `"`, `'`, `` ` ``).
51
+
52
+ === "CommonJS"
53
+
54
+ ```javascript
55
+ const { escapeHtml } = require('miki-template');
56
+
57
+ const escaped = escapeHtml('<script>');
58
+ // Output: &lt;script&gt;
59
+ ```
60
+
61
+ === "ES Modules"
62
+
63
+ ```javascript
64
+ import { escapeHtml } from 'miki-template';
65
+
66
+ const escaped = escapeHtml('<script>');
67
+ ```
68
+
69
+ ### Force-Escape SafeString
70
+
71
+ Pass `true` as the second argument to force-escape a `SafeString` (matching Django's `|escape` filter behavior):
72
+
73
+ === "CommonJS"
74
+
75
+ ```javascript
76
+ const { escapeHtml, SafeString } = require('miki-template');
77
+
78
+ const safe = new SafeString('<b>bold</b>');
79
+ const forced = escapeHtml(safe, true);
80
+ // Output: &lt;b&gt;bold&lt;/b&gt;
81
+ ```
82
+
83
+ === "ES Modules"
84
+
85
+ ```javascript
86
+ import { escapeHtml, SafeString } from 'miki-template';
87
+
88
+ const safe = new SafeString('<b>bold</b>');
89
+ const forced = escapeHtml(safe, true);
90
+ ```
91
+
92
+ ## stripExpressContext
93
+
94
+ Strip Express-specific framework keys (`_`, `settings`, `cache`) from a context object.
95
+
96
+ === "CommonJS"
97
+
98
+ ```javascript
99
+ const { stripExpressContext } = require('miki-template');
100
+
101
+ const cleanCtx = stripExpressContext(expressOptions);
102
+ // Removes: _locals, settings, cache, and other _ prefixed keys
103
+ ```
104
+
105
+ === "ES Modules"
106
+
107
+ ```javascript
108
+ import { stripExpressContext } from 'miki-template';
109
+
110
+ const cleanCtx = stripExpressContext(expressOptions);
111
+ ```
112
+
113
+ ## SafeString Class
114
+
115
+ Create a SafeString instance directly.
116
+
117
+ === "CommonJS"
118
+
119
+ ```javascript
120
+ const { SafeString } = require('miki-template');
121
+
122
+ const safe = new SafeString('<b>ok</b>');
123
+ ```
124
+
125
+ === "ES Modules"
126
+
127
+ ```javascript
128
+ import { SafeString } from 'miki-template';
129
+
130
+ const safe = new SafeString('<b>ok</b>');
131
+ ```
132
+
133
+ ## Path Traversal Protection
134
+
135
+ The `extends` and `include` tags validate that resolved template paths stay within configured views directories. Attempting to traverse outside throws an error:
136
+
137
+ ```html
138
+ {% extends "../../etc/passwd" %} <!-- throws -->
139
+ {% include "../../secrets" %} <!-- throws -->
140
+ ```
141
+
142
+ ## Next Steps
143
+
144
+ - [Security Guide](../guide/security)
145
+ - [API Reference](../)
@@ -0,0 +1,76 @@
1
+ # setupExpress()
2
+
3
+ One-line Express integration that wires the view engine, views directory, and partial responses.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ setupExpress(app, options = {})
9
+ ```
10
+
11
+ ## Options
12
+
13
+ | Option | Type | Description |
14
+ |--------|------|-------------|
15
+ | `extension` | `string` | View file extension, default `'html'` |
16
+ | `views` | `string\|string[]` | Views directory path(s) |
17
+ | `async` | `boolean` | Use async engine (`__expressAsync`) for Express 5+ |
18
+
19
+ ## What It Does
20
+
21
+ - Calls `app.engine()` with the miki view engine.
22
+ - Sets `app.set('view engine', extension)` if not already set.
23
+ - Sets `app.set('views', views)` if `options.views` is provided.
24
+ - Expands `views` to include nested template directories (app-style `templates/` folders).
25
+ - Patches `res.render` to support `view#partial` syntax for HTMX responses.
26
+
27
+ ## Example
28
+
29
+ === "CommonJS"
30
+
31
+ ```javascript
32
+ const express = require('express');
33
+ const miki = require('miki-template');
34
+
35
+ const app = express();
36
+ miki.setupExpress(app, { extension: 'html', views: './views' });
37
+
38
+ app.get('/', (req, res) => res.render('home', { user: req.user }));
39
+ app.get('/card/:id', (req, res) =>
40
+ res.render(`home#card`, { title: 'Hello' })
41
+ );
42
+
43
+ app.listen(3000);
44
+ ```
45
+
46
+ === "ES Modules"
47
+
48
+ ```javascript
49
+ import express from 'express';
50
+ import miki from 'miki-template';
51
+
52
+ const app = express();
53
+ miki.setupExpress(app, { extension: 'html', views: './views' });
54
+
55
+ app.get('/', (req, res) => res.render('home', { user: req.user }));
56
+ app.get('/card/:id', (req, res) =>
57
+ res.render(`home#card`, { title: 'Hello' })
58
+ );
59
+
60
+ app.listen(3000);
61
+ ```
62
+
63
+ ## Partial Responses
64
+
65
+ `setupExpress()` patches `res.render` so that any view name containing `#` renders only the named partial:
66
+
67
+ ```javascript
68
+ // Renders only the "card" partialdef from home.html
69
+ res.render('home#card', { title: 'Hello' });
70
+ ```
71
+
72
+ This is ideal for HTMX where you only need to update a portion of the page.
73
+
74
+ ## Related
75
+
76
+ - [Integrations: Express](../integrations/express)
@@ -0,0 +1,134 @@
1
+ # Tags API
2
+
3
+ ## registerTag
4
+
5
+ Register a custom tag callable from templates as `{% tag_name content %}...{% endtag_name %}`.
6
+
7
+ === "CommonJS"
8
+
9
+ ```javascript
10
+ const { registerTag } = require('miki-template');
11
+
12
+ registerTag('hello', (tagContent, parser) => {
13
+ return {
14
+ render: (context) => 'Hello World!'
15
+ };
16
+ });
17
+ ```
18
+
19
+ === "ES Modules"
20
+
21
+ ```javascript
22
+ import { registerTag } from 'miki-template';
23
+
24
+ registerTag('hello', (tagContent, parser) => {
25
+ return {
26
+ render: (context) => 'Hello World!'
27
+ };
28
+ });
29
+ ```
30
+
31
+ ### Tag Parser Signature
32
+
33
+ - `tagContent` — The full text after the tag name, as a string.
34
+ - `parser` — The Parser instance, providing `parser.parse()`, `parser.peek()`, `parser.skipTag()`.
35
+
36
+ Returns a **Node** object with a `render(context)` method. The render method receives the `Context` object and returns a string.
37
+
38
+ ## Built-in Tags
39
+
40
+ ### Control Flow
41
+
42
+ | Tag | Description |
43
+ |-----|-------------|
44
+ | `if / elif / else / endif` | Conditional blocks |
45
+ | `for / empty / endfor` | Loop over arrays/objects |
46
+ | `with / endwith` | Create a scoped context |
47
+ | `cycle` | Cycle through values |
48
+ | `firstof` | Output first non-empty value |
49
+ | `ifchanged / endifchanged` | Only output if value changed |
50
+
51
+ ### Variable Assignment
52
+
53
+ | Tag | Description |
54
+ |-----|-------------|
55
+ | `set var = expr` | Inline variable assignment |
56
+ | `set var %}...{% endset` | Capture block output into a variable |
57
+
58
+ ### Date and Time
59
+
60
+ | Tag | Description |
61
+ |-----|-------------|
62
+ | `now "Y-m-d H:i:s"` | Output current date/time |
63
+
64
+ ### Utility
65
+
66
+ | Tag | Description |
67
+ |-----|-------------|
68
+ | `static "path"` | Resolve static asset path |
69
+ | `url 'route.name' arg1 arg2` | Generate URL by route name |
70
+ | `regroup list by attr as name` | Regroup a list by an attribute |
71
+ | `spaceless / endspaceless` | Remove whitespace between HTML tags |
72
+ | `widthratio value max max_width` | Calculate CSS width ratio |
73
+ | `debug` | Output debugging context information |
74
+
75
+ ### Security
76
+
77
+ | Tag | Description |
78
+ |-----|-------------|
79
+ | `csrf_token` | Output CSRF hidden input |
80
+ | `csp_nonce_attr` | Output `nonce` attribute for CSP |
81
+
82
+ ### Comments and Raw Output
83
+
84
+ | Tag | Description |
85
+ |-----|-------------|
86
+ | `comment / endcomment` | Comment out content |
87
+ | `verbatim / endverbatim` | Disable tag parsing within |
88
+
89
+ ### Autoescape
90
+
91
+ | Tag | Description |
92
+ |-----|-------------|
93
+ | `autoescape on / off / endautoescape` | Toggle HTML escaping |
94
+
95
+ ### Library Loading
96
+
97
+ | Tag | Description |
98
+ |-----|-------------|
99
+ | `load library_name` | Load a registered library |
100
+
101
+ ### Template Tags
102
+
103
+ | Tag | Description |
104
+ |-----|-------------|
105
+ | `templatetag token` | Output a template syntax character (e.g. `{% templatetag openpercentblock %}`) |
106
+
107
+ ### Inheritance
108
+
109
+ | Tag | Description |
110
+ |-----|-------------|
111
+ | `extends "parent.html"` | Inherit from a parent template |
112
+ | `block name / endblock` | Define/overriding inheritable block |
113
+ | `include "file.html"` | Include another template |
114
+
115
+ ### Partials
116
+
117
+ | Tag | Description |
118
+ |-----|-------------|
119
+ | `partialdef name / endpartialdef` | Define a named partial |
120
+ | `partial name with k=v` | Render a defined partial |
121
+
122
+ ### i18n
123
+
124
+ | Tag | Description |
125
+ |-----|-------------|
126
+ | `trans "key"` | Translate a string |
127
+ | `blocktrans / endblocktrans` | Translate with variables |
128
+ | `language "xx" / endlanguage` | Switch language for a block |
129
+
130
+ ## Next Steps
131
+
132
+ - [Tags Guide](../guide/tags)
133
+ - [Custom Tags](../guide/custom-tags)
134
+ - [API Reference](../)
Binary file
Binary file