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,92 +1,184 @@
1
- # render()
1
+ # render()
2
+
3
+
2
4
 
3
5
  Render a template string or file partial.
4
6
 
7
+
8
+
5
9
  ## Signature
6
10
 
11
+
12
+
7
13
  ```javascript
14
+
8
15
  render(templateStr, contextObj = {}, options = {})
16
+
9
17
  ```
10
18
 
19
+
20
+
11
21
  ## Parameters
12
22
 
23
+
24
+
13
25
  | Parameter | Type | Description |
26
+
14
27
  |-----------|------|-------------|
28
+
15
29
  | `templateStr` | `string` | Template string or file path with `#partial` suffix |
30
+
16
31
  | `contextObj` | `object` | Variables to inject into the template |
32
+
17
33
  | `options` | `object` | Options including `views` directories and custom settings |
18
34
 
35
+
36
+
19
37
  ## Returns
20
38
 
39
+
40
+
21
41
  `string` — The rendered HTML.
22
42
 
43
+
44
+
23
45
  ## Examples
24
46
 
47
+
48
+
25
49
  ### Render a template string
26
50
 
51
+
52
+
27
53
  === "CommonJS"
28
54
 
55
+
56
+
29
57
  ```javascript
58
+
30
59
  const { render } = require('miki-template');
31
60
 
61
+
62
+
32
63
  const html = render('Hello {{ name }}!', { name: 'World' });
64
+
33
65
  // Output: Hello World!
66
+
34
67
  ```
35
68
 
69
+
70
+
36
71
  === "ES Modules"
37
72
 
73
+
74
+
38
75
  ```javascript
76
+
39
77
  import { render } from 'miki-template';
40
78
 
79
+
80
+
41
81
  const html = render('Hello {{ name }}!', { name: 'World' });
82
+
42
83
  // Output: Hello World!
84
+
43
85
  ```
44
86
 
87
+
88
+
45
89
  ### Render a partial from file
46
90
 
91
+
92
+
47
93
  === "CommonJS"
48
94
 
95
+
96
+
49
97
  ```javascript
98
+
50
99
  const { render } = require('miki-template');
51
100
 
101
+
102
+
52
103
  const html = render('home#card', { title: 'Hello' }, { views: './views' });
104
+
53
105
  ```
54
106
 
107
+
108
+
55
109
  === "ES Modules"
56
110
 
111
+
112
+
57
113
  ```javascript
114
+
58
115
  import { render } from 'miki-template';
59
116
 
117
+
118
+
60
119
  const html = render('home#card', { title: 'Hello' }, { views: './views' });
120
+
61
121
  ```
62
122
 
123
+
124
+
63
125
  ### Render with options
64
126
 
127
+
128
+
65
129
  === "CommonJS"
66
130
 
131
+
132
+
67
133
  ```javascript
134
+
68
135
  const { render } = require('miki-template');
69
136
 
137
+
138
+
70
139
  const html = render(template, context, {
140
+
71
141
  views: ['./views', './app/templates'],
142
+
72
143
  staticUrl: '/static',
144
+
73
145
  urlHelper: (name, ...args) => '/' + name + '/' + args.join('/')
146
+
74
147
  });
148
+
75
149
  ```
76
150
 
151
+
152
+
77
153
  === "ES Modules"
78
154
 
155
+
156
+
79
157
  ```javascript
158
+
80
159
  import { render } from 'miki-template';
81
160
 
161
+
162
+
82
163
  const html = render(template, context, {
164
+
83
165
  views: ['./views', './app/templates'],
166
+
84
167
  staticUrl: '/static',
168
+
85
169
  urlHelper: (name, ...args) => '/' + name + '/' + args.join('/')
170
+
86
171
  });
172
+
87
173
  ```
88
174
 
175
+
176
+
89
177
  ## Related
90
178
 
91
- - [compile()](./compile)
92
- - [asyncRender()](./async-render)
179
+
180
+
181
+ - [compile()](./compile.md)
182
+
183
+ - [asyncRender()](./async-render.md)
184
+
@@ -1,145 +1,290 @@
1
- # Security API
1
+ # Security API
2
+
3
+
2
4
 
3
5
  ## markSafe
4
6
 
7
+
8
+
5
9
  Mark a string as safe (bypass auto-escaping).
6
10
 
11
+
12
+
7
13
  === "CommonJS"
8
14
 
15
+
16
+
9
17
  ```javascript
18
+
10
19
  const { markSafe } = require('miki-template');
11
20
 
21
+
22
+
12
23
  const html = markSafe('<b>ok</b>');
24
+
13
25
  // Will not be escaped
26
+
14
27
  ```
15
28
 
29
+
30
+
16
31
  === "ES Modules"
17
32
 
33
+
34
+
18
35
  ```javascript
36
+
19
37
  import { markSafe } from 'miki-template';
20
38
 
39
+
40
+
21
41
  const html = markSafe('<b>ok</b>');
42
+
22
43
  ```
23
44
 
45
+
46
+
24
47
  ## isSafe
25
48
 
49
+
50
+
26
51
  Check if a value is marked safe.
27
52
 
53
+
54
+
28
55
  === "CommonJS"
29
56
 
57
+
58
+
30
59
  ```javascript
60
+
31
61
  const { isSafe } = require('miki-template');
32
62
 
63
+
64
+
33
65
  if (isSafe(value)) {
66
+
34
67
  // value is marked safe
68
+
35
69
  }
70
+
36
71
  ```
37
72
 
73
+
74
+
38
75
  === "ES Modules"
39
76
 
77
+
78
+
40
79
  ```javascript
80
+
41
81
  import { isSafe } from 'miki-template';
42
82
 
83
+
84
+
43
85
  if (isSafe(value)) {
86
+
44
87
  // value is marked safe
88
+
45
89
  }
90
+
46
91
  ```
47
92
 
93
+
94
+
48
95
  ## escapeHtml
49
96
 
97
+
98
+
50
99
  Escape HTML special characters (`&`, `<`, `>`, `"`, `'`, `` ` ``).
51
100
 
101
+
102
+
52
103
  === "CommonJS"
53
104
 
105
+
106
+
54
107
  ```javascript
108
+
55
109
  const { escapeHtml } = require('miki-template');
56
110
 
111
+
112
+
57
113
  const escaped = escapeHtml('<script>');
114
+
58
115
  // Output: &lt;script&gt;
116
+
59
117
  ```
60
118
 
119
+
120
+
61
121
  === "ES Modules"
62
122
 
123
+
124
+
63
125
  ```javascript
126
+
64
127
  import { escapeHtml } from 'miki-template';
65
128
 
129
+
130
+
66
131
  const escaped = escapeHtml('<script>');
132
+
67
133
  ```
68
134
 
135
+
136
+
69
137
  ### Force-Escape SafeString
70
138
 
139
+
140
+
71
141
  Pass `true` as the second argument to force-escape a `SafeString` (matching Django's `|escape` filter behavior):
72
142
 
143
+
144
+
73
145
  === "CommonJS"
74
146
 
147
+
148
+
75
149
  ```javascript
150
+
76
151
  const { escapeHtml, SafeString } = require('miki-template');
77
152
 
153
+
154
+
78
155
  const safe = new SafeString('<b>bold</b>');
156
+
79
157
  const forced = escapeHtml(safe, true);
158
+
80
159
  // Output: &lt;b&gt;bold&lt;/b&gt;
160
+
81
161
  ```
82
162
 
163
+
164
+
83
165
  === "ES Modules"
84
166
 
167
+
168
+
85
169
  ```javascript
170
+
86
171
  import { escapeHtml, SafeString } from 'miki-template';
87
172
 
173
+
174
+
88
175
  const safe = new SafeString('<b>bold</b>');
176
+
89
177
  const forced = escapeHtml(safe, true);
178
+
90
179
  ```
91
180
 
181
+
182
+
92
183
  ## stripExpressContext
93
184
 
185
+
186
+
94
187
  Strip Express-specific framework keys (`_`, `settings`, `cache`) from a context object.
95
188
 
189
+
190
+
96
191
  === "CommonJS"
97
192
 
193
+
194
+
98
195
  ```javascript
196
+
99
197
  const { stripExpressContext } = require('miki-template');
100
198
 
199
+
200
+
101
201
  const cleanCtx = stripExpressContext(expressOptions);
202
+
102
203
  // Removes: _locals, settings, cache, and other _ prefixed keys
204
+
103
205
  ```
104
206
 
207
+
208
+
105
209
  === "ES Modules"
106
210
 
211
+
212
+
107
213
  ```javascript
214
+
108
215
  import { stripExpressContext } from 'miki-template';
109
216
 
217
+
218
+
110
219
  const cleanCtx = stripExpressContext(expressOptions);
220
+
111
221
  ```
112
222
 
223
+
224
+
113
225
  ## SafeString Class
114
226
 
227
+
228
+
115
229
  Create a SafeString instance directly.
116
230
 
231
+
232
+
117
233
  === "CommonJS"
118
234
 
235
+
236
+
119
237
  ```javascript
238
+
120
239
  const { SafeString } = require('miki-template');
121
240
 
241
+
242
+
122
243
  const safe = new SafeString('<b>ok</b>');
244
+
123
245
  ```
124
246
 
247
+
248
+
125
249
  === "ES Modules"
126
250
 
251
+
252
+
127
253
  ```javascript
254
+
128
255
  import { SafeString } from 'miki-template';
129
256
 
257
+
258
+
130
259
  const safe = new SafeString('<b>ok</b>');
260
+
131
261
  ```
132
262
 
263
+
264
+
133
265
  ## Path Traversal Protection
134
266
 
267
+
268
+
135
269
  The `extends` and `include` tags validate that resolved template paths stay within configured views directories. Attempting to traverse outside throws an error:
136
270
 
271
+
272
+
137
273
  ```html
274
+
138
275
  {% extends "../../etc/passwd" %} <!-- throws -->
276
+
139
277
  {% include "../../secrets" %} <!-- throws -->
278
+
140
279
  ```
141
280
 
281
+
282
+
142
283
  ## Next Steps
143
284
 
144
- - [Security Guide](../guide/security)
145
- - [API Reference](../)
285
+
286
+
287
+ - [Security Guide](../guide/security.md)
288
+
289
+ - [API Reference](../index.md)
290
+
@@ -1,76 +1,152 @@
1
- # setupExpress()
1
+ # setupExpress()
2
+
3
+
2
4
 
3
5
  One-line Express integration that wires the view engine, views directory, and partial responses.
4
6
 
7
+
8
+
5
9
  ## Signature
6
10
 
11
+
12
+
7
13
  ```javascript
14
+
8
15
  setupExpress(app, options = {})
16
+
9
17
  ```
10
18
 
19
+
20
+
11
21
  ## Options
12
22
 
23
+
24
+
13
25
  | Option | Type | Description |
26
+
14
27
  |--------|------|-------------|
28
+
15
29
  | `extension` | `string` | View file extension, default `'html'` |
30
+
16
31
  | `views` | `string\|string[]` | Views directory path(s) |
32
+
17
33
  | `async` | `boolean` | Use async engine (`__expressAsync`) for Express 5+ |
18
34
 
35
+
36
+
19
37
  ## What It Does
20
38
 
39
+
40
+
21
41
  - Calls `app.engine()` with the miki view engine.
42
+
22
43
  - Sets `app.set('view engine', extension)` if not already set.
44
+
23
45
  - Sets `app.set('views', views)` if `options.views` is provided.
46
+
24
47
  - Expands `views` to include nested template directories (app-style `templates/` folders).
48
+
25
49
  - Patches `res.render` to support `view#partial` syntax for HTMX responses.
26
50
 
51
+
52
+
27
53
  ## Example
28
54
 
55
+
56
+
29
57
  === "CommonJS"
30
58
 
59
+
60
+
31
61
  ```javascript
62
+
32
63
  const express = require('express');
64
+
33
65
  const miki = require('miki-template');
34
66
 
67
+
68
+
35
69
  const app = express();
70
+
36
71
  miki.setupExpress(app, { extension: 'html', views: './views' });
37
72
 
73
+
74
+
38
75
  app.get('/', (req, res) => res.render('home', { user: req.user }));
76
+
39
77
  app.get('/card/:id', (req, res) =>
78
+
40
79
  res.render(`home#card`, { title: 'Hello' })
80
+
41
81
  );
42
82
 
83
+
84
+
43
85
  app.listen(3000);
86
+
44
87
  ```
45
88
 
89
+
90
+
46
91
  === "ES Modules"
47
92
 
93
+
94
+
48
95
  ```javascript
96
+
49
97
  import express from 'express';
98
+
50
99
  import miki from 'miki-template';
51
100
 
101
+
102
+
52
103
  const app = express();
104
+
53
105
  miki.setupExpress(app, { extension: 'html', views: './views' });
54
106
 
107
+
108
+
55
109
  app.get('/', (req, res) => res.render('home', { user: req.user }));
110
+
56
111
  app.get('/card/:id', (req, res) =>
112
+
57
113
  res.render(`home#card`, { title: 'Hello' })
114
+
58
115
  );
59
116
 
117
+
118
+
60
119
  app.listen(3000);
120
+
61
121
  ```
62
122
 
123
+
124
+
63
125
  ## Partial Responses
64
126
 
127
+
128
+
65
129
  `setupExpress()` patches `res.render` so that any view name containing `#` renders only the named partial:
66
130
 
131
+
132
+
67
133
  ```javascript
134
+
68
135
  // Renders only the "card" partialdef from home.html
136
+
69
137
  res.render('home#card', { title: 'Hello' });
138
+
70
139
  ```
71
140
 
141
+
142
+
72
143
  This is ideal for HTMX where you only need to update a portion of the page.
73
144
 
145
+
146
+
74
147
  ## Related
75
148
 
76
- - [Integrations: Express](../integrations/express)
149
+
150
+
151
+ - [Integrations: Express](../integrations/express.md)
152
+