miki-template 2.2.2 → 2.3.0

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 +1 -0
  3. package/benchmarks/ejs-results.json +6 -6
  4. package/benchmarks/ejs.js +5 -3
  5. package/benchmarks/handlebars-results.json +6 -6
  6. package/benchmarks/handlebars.js +5 -8
  7. package/benchmarks/miki-results.json +6 -6
  8. package/benchmarks/miki.js +6 -3
  9. package/benchmarks/pug-results.json +6 -6
  10. package/benchmarks/pug.js +5 -3
  11. package/docs/api/async-render.md +88 -3
  12. package/docs/api/cache.md +90 -3
  13. package/docs/api/compile.md +131 -3
  14. package/docs/api/context-processors.md +80 -3
  15. package/docs/api/filters.md +223 -3
  16. package/docs/api/finder.md +97 -3
  17. package/docs/api/helpers.md +56 -3
  18. package/docs/api/i18n.md +160 -3
  19. package/docs/api/index.md +82 -28
  20. package/docs/api/libraries.md +210 -3
  21. package/docs/api/render-partial.md +84 -3
  22. package/docs/api/render.md +95 -3
  23. package/docs/api/security.md +148 -3
  24. package/docs/api/setup-express.md +78 -2
  25. package/docs/api/tags.md +138 -4
  26. package/docs/filter.md +0 -0
  27. package/docs/guide/advanced-usage.md +403 -6
  28. package/docs/guide/async-rendering.md +312 -4
  29. package/docs/guide/context-processors.md +261 -4
  30. package/docs/guide/custom-filters.md +315 -4
  31. package/docs/guide/custom-tags.md +275 -4
  32. package/docs/guide/filters.md +675 -3
  33. package/docs/guide/getting-started.md +109 -7
  34. package/docs/guide/installation.md +99 -4
  35. package/docs/guide/partial-templates.md +371 -4
  36. package/docs/guide/quick-start.md +228 -6
  37. package/docs/guide/security.md +348 -3
  38. package/docs/guide/tags.md +789 -6
  39. package/docs/guide/template-discovery.md +174 -4
  40. package/docs/guide/template-inheritance.md +277 -4
  41. package/docs/index.md +24 -42
  42. package/docs/integrations/elysia.md +4 -2
  43. package/docs/integrations/express.md +219 -219
  44. package/docs/integrations/fastify.md +4 -2
  45. package/docs/integrations/hono.md +4 -2
  46. package/docs/integrations/index.md +68 -68
  47. package/docs/integrations/koa.md +4 -2
  48. package/docs/integrations/nestjs.md +4 -2
  49. package/docs/integrations/tsed.md +4 -2
  50. package/docs/performance.md +45 -8
  51. package/ex.mjs +1 -1
  52. package/mkdocs.yml +0 -22
  53. package/overrides/main.html +1 -1
  54. package/package.json +1 -1
  55. package/requirements-docs.txt +2 -1
  56. package/src/codegen.js +905 -0
  57. package/src/context.js +42 -30
  58. package/src/filters.js +16 -0
  59. package/src/index.js +66 -61
  60. package/src/tags/control.js +15 -12
  61. package/src/utils.js +60 -0
  62. package/tests/filters.test.js +9 -0
  63. package/.github/workflows/npm-publish-github-packages.yml +0 -36
  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,257 +1,514 @@
1
- # Context Processors
1
+ # Context Processors
2
+
3
+
2
4
 
3
5
  Context processors are functions that automatically inject variables into every template render. This follows Django's context processor pattern — ideal for injecting global settings, user data, or feature flags.
4
6
 
7
+
8
+
5
9
  ## Table of Contents
6
10
 
11
+
12
+
7
13
  - [How Context Processors Work](#how-context-processors-work)
14
+
8
15
  - [Register a Context Processor](#register-a-context-processor)
16
+
9
17
  - [Context Processor Signature](#context-processor-signature)
18
+
10
19
  - [Overriding Behavior](#overriding-behavior)
20
+
11
21
  - [Real-World Examples](#real-world-examples)
22
+
12
23
  - [Clearing Processors](#clearing-processors)
13
24
 
25
+
26
+
14
27
  ---
15
28
 
29
+
30
+
16
31
  ## How Context Processors Work
17
32
 
33
+
34
+
18
35
  Context processors run on **every render** (both `render()` and `compile().render()`). They return an object of key/value pairs that are merged into the rendering context **before** your template's local context is applied.
19
36
 
37
+
38
+
20
39
  ```mermaid
40
+
21
41
  graph LR
42
+
22
43
  A[Your Context] --> B[Apply Processors]
44
+
23
45
  B --> C[Processor adds global vars]
46
+
24
47
  C --> D[Your Context wins]
48
+
25
49
  D --> E[Template renders]
50
+
26
51
  ```
27
52
 
53
+
54
+
28
55
  **Key behavior:** Your explicit context values **always win** over processor values. This means you can override global defaults per-render without fighting the processor.
29
56
 
57
+
58
+
30
59
  ## Register a Context Processor
31
60
 
61
+
62
+
32
63
  === "CommonJS"
33
64
 
65
+
66
+
34
67
  ```javascript
68
+
35
69
  const { registerContextProcessor } = require('miki-template');
36
70
 
71
+
72
+
37
73
  registerContextProcessor((context) => {
74
+
38
75
  return {
76
+
39
77
  siteName: 'My App',
78
+
40
79
  currentYear: new Date().getFullYear(),
80
+
41
81
  debug: process.env.NODE_ENV !== 'production'
82
+
42
83
  };
84
+
43
85
  });
86
+
44
87
  ```
45
88
 
89
+
90
+
46
91
  === "ES Modules"
47
92
 
93
+
94
+
48
95
  ```javascript
96
+
49
97
  import { registerContextProcessor } from 'miki-template';
50
98
 
99
+
100
+
51
101
  registerContextProcessor((context) => {
102
+
52
103
  return {
104
+
53
105
  siteName: 'My App',
106
+
54
107
  currentYear: new Date().getFullYear(),
108
+
55
109
  debug: process.env.NODE_ENV !== 'production'
110
+
56
111
  };
112
+
57
113
  });
114
+
58
115
  ```
59
116
 
117
+
118
+
60
119
  ### Multiple Processors
61
120
 
121
+
122
+
62
123
  You can register multiple processors. They run in order — later processors can overwrite earlier ones:
63
124
 
125
+
126
+
64
127
  === "CommonJS"
65
128
 
129
+
130
+
66
131
  ```javascript
132
+
67
133
  const { registerContextProcessor } = require('miki-template');
68
134
 
135
+
136
+
69
137
  registerContextProcessor(() => ({ siteName: 'My App' }));
138
+
70
139
  registerContextProcessor(() => ({ version: '2.0.0' }));
140
+
71
141
  registerContextProcessor(() => ({
142
+
72
143
  footerText: '© 2024 My App. All rights reserved.'
144
+
73
145
  }));
146
+
74
147
  ```
75
148
 
149
+
150
+
76
151
  === "ES Modules"
77
152
 
153
+
154
+
78
155
  ```javascript
156
+
79
157
  import { registerContextProcessor } from 'miki-template';
80
158
 
159
+
160
+
81
161
  registerContextProcessor(() => ({ siteName: 'My App' }));
162
+
82
163
  registerContextProcessor(() => ({ version: '2.0.0' }));
164
+
83
165
  registerContextProcessor(() => ({
166
+
84
167
  footerText: '© 2024 My App. All rights reserved.'
168
+
85
169
  }));
170
+
86
171
  ```
87
172
 
173
+
174
+
88
175
  ## Context Processor Signature
89
176
 
177
+
178
+
90
179
  The processor function receives the rendering `context` as an argument and must return a plain object:
91
180
 
181
+
182
+
92
183
  ```javascript
184
+
93
185
  registerContextProcessor((context) => {
186
+
94
187
  // context is the full Context object — you can inspect contextObj
188
+
95
189
  // but don't mutate it
190
+
96
191
  return {
192
+
97
193
  key: 'value'
194
+
98
195
  };
196
+
99
197
  });
198
+
100
199
  ```
101
200
 
201
+
202
+
102
203
  **Important:** If a processor returns `null`, `undefined`, or nothing, it's treated as returning an empty object `{}`. Processors must **not** return a Promise — if you need async data, compute it before rendering and pass it as context.
103
204
 
205
+
206
+
104
207
  ## Overriding Behavior
105
208
 
209
+
210
+
106
211
  Since your explicit context always wins, you can override global defaults per-render:
107
212
 
213
+
214
+
108
215
  === "CommonJS"
109
216
 
217
+
218
+
110
219
  ```javascript
220
+
111
221
  const { render } = require('miki-template');
112
222
 
223
+
224
+
113
225
  // processor sets debug: false
226
+
114
227
  // but this render overrides it:
228
+
115
229
  render(template, { debug: true });
230
+
116
231
  ```
117
232
 
233
+
234
+
118
235
  === "ES Modules"
119
236
 
237
+
238
+
120
239
  ```javascript
240
+
121
241
  import { render } from 'miki-template';
122
242
 
243
+
244
+
123
245
  render(template, { debug: true });
246
+
124
247
  ```
125
248
 
249
+
250
+
126
251
  ## Real-World Examples
127
252
 
253
+
254
+
128
255
  ### App-wide Settings
129
256
 
257
+
258
+
130
259
  === "CommonJS"
131
260
 
261
+
262
+
132
263
  ```javascript
264
+
133
265
  const { registerContextProcessor } = require('miki-template');
134
266
 
267
+
268
+
135
269
  registerContextProcessor(() => ({
270
+
136
271
  appName: process.env.APP_NAME || 'MyApp',
272
+
137
273
  appVersion: require('./package.json').version,
274
+
138
275
  environment: process.env.NODE_ENV || 'development',
276
+
139
277
  apiUrl: process.env.API_URL || 'http://localhost:3000/api',
278
+
140
279
  assetsUrl: process.env.ASSETS_URL || '/assets'
280
+
141
281
  }));
282
+
142
283
  ```
143
284
 
285
+
286
+
144
287
  === "ES Modules"
145
288
 
289
+
290
+
146
291
  ```javascript
292
+
147
293
  import { registerContextProcessor } from 'miki-template';
294
+
148
295
  import pkg from './package.json' with { type: 'json' };
149
296
 
297
+
298
+
150
299
  registerContextProcessor(() => ({
300
+
151
301
  appName: process.env.APP_NAME || 'MyApp',
302
+
152
303
  appVersion: pkg.version,
304
+
153
305
  environment: process.env.NODE_ENV || 'development',
306
+
154
307
  apiUrl: process.env.API_URL || 'http://localhost:3000/api',
308
+
155
309
  assetsUrl: process.env.ASSETS_URL || '/assets'
310
+
156
311
  }));
312
+
157
313
  ```
158
314
 
315
+
316
+
159
317
  ### User Authentication
160
318
 
319
+
320
+
161
321
  === "CommonJS"
162
322
 
323
+
324
+
163
325
  ```javascript
326
+
164
327
  const { registerContextProcessor } = require('miki-template');
165
328
 
329
+
330
+
166
331
  registerContextProcessor((context) => {
332
+
167
333
  const user = context.get('user');
334
+
168
335
  if (!user) return {};
336
+
169
337
  return {
338
+
170
339
  user_name: user.name,
340
+
171
341
  user_avatar: user.avatar || '/default-avatar.png',
342
+
172
343
  user_is_admin: user.isAdmin || false
344
+
173
345
  };
346
+
174
347
  });
348
+
175
349
  ```
176
350
 
351
+
352
+
177
353
  === "ES Modules"
178
354
 
355
+
356
+
179
357
  ```javascript
358
+
180
359
  import { registerContextProcessor } from 'miki-template';
181
360
 
361
+
362
+
182
363
  registerContextProcessor((context) => {
364
+
183
365
  const user = context.get('user');
366
+
184
367
  if (!user) return {};
368
+
185
369
  return {
370
+
186
371
  user_name: user.name,
372
+
187
373
  user_avatar: user.avatar || '/default-avatar.png',
374
+
188
375
  user_is_admin: user.isAdmin || false
376
+
189
377
  };
378
+
190
379
  });
380
+
191
381
  ```
192
382
 
383
+
384
+
193
385
  ### Feature Flags
194
386
 
387
+
388
+
195
389
  === "CommonJS"
196
390
 
391
+
392
+
197
393
  ```javascript
394
+
198
395
  const { registerContextProcessor } = require('miki-template');
199
396
 
397
+
398
+
200
399
  registerContextProcessor(() => ({
400
+
201
401
  flags: {
402
+
202
403
  newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
404
+
203
405
  betaFeature: process.env.FEATURE_BETA === 'true',
406
+
204
407
  darkModeDefault: process.env.FEATURE_DARK_MODE === 'true'
408
+
205
409
  }
410
+
206
411
  }));
412
+
207
413
  ```
208
414
 
415
+
416
+
209
417
  === "ES Modules"
210
418
 
419
+
420
+
211
421
  ```javascript
422
+
212
423
  import { registerContextProcessor } from 'miki-template';
213
424
 
425
+
426
+
214
427
  registerContextProcessor(() => ({
428
+
215
429
  flags: {
430
+
216
431
  newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
432
+
217
433
  betaFeature: process.env.FEATURE_BETA === 'true',
434
+
218
435
  darkModeDefault: process.env.FEATURE_DARK_MODE === 'true'
436
+
219
437
  }
438
+
220
439
  }));
440
+
221
441
  ```
222
442
 
443
+
444
+
223
445
  Template usage:
224
446
 
447
+
448
+
225
449
  ```html
450
+
226
451
  {% if flags.newDashboard %}
452
+
227
453
  <a href="/new-dashboard">New Dashboard</a>
454
+
228
455
  {% else %}
456
+
229
457
  <a href="/dashboard">Classic Dashboard</a>
458
+
230
459
  {% endif %}
460
+
231
461
  ```
232
462
 
463
+
464
+
233
465
  ## Clearing Processors
234
466
 
467
+
468
+
235
469
  Clear all registered processors (useful in tests or dynamic configuration):
236
470
 
471
+
472
+
237
473
  === "CommonJS"
238
474
 
475
+
476
+
239
477
  ```javascript
478
+
240
479
  const { clearContextProcessors } = require('miki-template');
241
480
 
481
+
482
+
242
483
  clearContextProcessors();
484
+
243
485
  ```
244
486
 
487
+
488
+
245
489
  === "ES Modules"
246
490
 
491
+
492
+
247
493
  ```javascript
494
+
248
495
  import { clearContextProcessors } from 'miki-template';
249
496
 
497
+
498
+
250
499
  clearContextProcessors();
500
+
251
501
  ```
252
502
 
503
+
504
+
253
505
  ## Next Steps
254
506
 
255
- - [Advanced Usage: Context Processors](./advanced-usage)
256
- - [Async Rendering](./async-rendering)
257
- - [API Reference: Context Processors](../api/context-processors)
507
+
508
+
509
+ - [Advanced Usage: Context Processors](./advanced-usage.md)
510
+
511
+ - [Async Rendering](./async-rendering.md)
512
+
513
+ - [API Reference: Context Processors](../api/context-processors.md)
514
+