miki-template 2.0.1 → 2.2.2
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/.github/workflows/ci.yml +13 -37
- package/.github/workflows/docs.yml +105 -0
- package/.github/workflows/npm-publish-github-packages.yml +36 -0
- package/README.md +69 -14
- package/assets/logo.png +0 -0
- package/benchmarks/ejs-results.json +4 -4
- package/benchmarks/handlebars-results.json +6 -6
- package/benchmarks/miki-results.json +4 -4
- package/benchmarks/pug-results.json +4 -4
- package/benchmarks/stress.mjs +1 -1
- package/docs/api/async-render.md +85 -0
- package/docs/api/cache.md +87 -0
- package/docs/api/compile.md +128 -0
- package/docs/api/context-processors.md +77 -0
- package/docs/api/filters.md +217 -0
- package/docs/api/finder.md +94 -0
- package/docs/api/helpers.md +53 -0
- package/docs/api/i18n.md +157 -0
- package/docs/api/index.md +54 -0
- package/docs/api/libraries.md +207 -0
- package/docs/api/render-partial.md +81 -0
- package/docs/api/render.md +92 -0
- package/docs/api/security.md +145 -0
- package/docs/api/setup-express.md +76 -0
- package/docs/api/tags.md +134 -0
- package/docs/assets/banner.png +0 -0
- package/docs/assets/logo.png +0 -0
- package/docs/guide/advanced-usage.md +397 -0
- package/docs/guide/async-rendering.md +308 -0
- package/docs/guide/context-processors.md +257 -0
- package/docs/guide/custom-filters.md +311 -0
- package/docs/guide/custom-tags.md +271 -0
- package/docs/guide/filters.md +642 -0
- package/docs/guide/getting-started.md +102 -0
- package/docs/guide/installation.md +95 -0
- package/docs/guide/partial-templates.md +367 -0
- package/docs/guide/quick-start.md +222 -0
- package/docs/guide/security.md +345 -0
- package/docs/guide/tags.md +783 -0
- package/docs/guide/template-discovery.md +170 -0
- package/docs/guide/template-inheritance.md +273 -0
- package/docs/guide/what-is-miki-template.md +28 -0
- package/docs/guide/why-miki-template.md +75 -0
- package/docs/index.md +104 -0
- package/docs/integrations/elysia.md +78 -0
- package/docs/integrations/express.md +219 -0
- package/docs/integrations/fastify.md +77 -0
- package/docs/integrations/hono.md +78 -0
- package/docs/integrations/index.md +68 -0
- package/docs/integrations/koa.md +88 -0
- package/docs/integrations/nestjs.md +78 -0
- package/docs/integrations/tsed.md +81 -0
- package/docs/javascripts/extra.js +174 -0
- package/docs/performance.md +37 -0
- package/docs/stylesheets/extra.css +819 -0
- package/mkdocs.yml +217 -0
- package/overrides/main.html +26 -0
- package/overrides/partials/footer.html +9 -0
- package/package.json +4 -2
- package/requirements-docs.txt +1 -0
- package/docs/README.md +0 -18
- package/docs/advanced_usage.md +0 -71
- package/docs/api.md +0 -122
- package/docs/filters.md +0 -708
- package/docs/installation.md +0 -106
- package/docs/integrations.md +0 -214
- package/docs/overview.md +0 -79
- package/docs/partialdef.md +0 -70
- package/docs/security.md +0 -27
- package/docs/tags.md +0 -673
- 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: <script>
|
|
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: <b>bold</b>
|
|
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)
|
package/docs/api/tags.md
ADDED
|
@@ -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
|