miki-template 2.3.1 → 2.3.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/package.json +45 -1
- package/.eslintrc.json +0 -16
- package/.github/release-notes/v1.3.1.md +0 -55
- package/.github/release-notes/v1.3.3.md +0 -77
- package/.github/release-notes/v1.3.7.md +0 -20
- package/.github/workflows/ci.yml +0 -42
- package/.github/workflows/docs.yml +0 -107
- package/.github/workflows/release.yml +0 -107
- package/AGENT.md +0 -71
- package/API_REFERENCE.md +0 -341
- package/CHANGELOG.md +0 -173
- package/CODE_OF_CONDUCT.md +0 -14
- package/CONTRIBUTING.md +0 -27
- package/ROADMAP.md +0 -40
- package/assets/banner.png +0 -0
- package/assets/logo.png +0 -0
- package/benchmarks/ejs-results.json +0 -17
- package/benchmarks/ejs.js +0 -38
- package/benchmarks/handlebars-results.json +0 -17
- package/benchmarks/handlebars.js +0 -45
- package/benchmarks/miki-results.json +0 -17
- package/benchmarks/miki.js +0 -39
- package/benchmarks/pug-results.json +0 -17
- package/benchmarks/pug.js +0 -38
- package/benchmarks/report.json +0 -17
- package/benchmarks/run.js +0 -81
- package/benchmarks/stress.mjs +0 -647
- package/benchmarks/templates/large.dtpl +0 -7
- package/benchmarks/templates/medium.dtpl +0 -3
- package/benchmarks/templates/small.dtpl +0 -7
- package/context/component.md +0 -109
- package/context/prd.md +0 -131
- package/context/project-structure.md +0 -33
- package/dir/base.html +0 -23
- package/dir/cmpnt.html +0 -11
- package/dir/footer.html +0 -3
- package/dir/home.html +0 -80
- package/dir/index.html +0 -80
- package/dir/navbar.html +0 -9
- package/docs/api/async-render.md +0 -170
- package/docs/api/cache.md +0 -174
- package/docs/api/compile.md +0 -256
- package/docs/api/context-processors.md +0 -154
- package/docs/api/filters.md +0 -437
- package/docs/api/finder.md +0 -188
- package/docs/api/helpers.md +0 -106
- package/docs/api/i18n.md +0 -314
- package/docs/api/index.md +0 -108
- package/docs/api/libraries.md +0 -414
- package/docs/api/render-partial.md +0 -162
- package/docs/api/render.md +0 -184
- package/docs/api/security.md +0 -290
- package/docs/api/setup-express.md +0 -152
- package/docs/api/tags.md +0 -268
- package/docs/assets/banner.png +0 -0
- package/docs/assets/logo.png +0 -0
- package/docs/filter.md +0 -0
- package/docs/guide/advanced-usage.md +0 -794
- package/docs/guide/async-rendering.md +0 -616
- package/docs/guide/context-processors.md +0 -514
- package/docs/guide/custom-filters.md +0 -622
- package/docs/guide/custom-tags.md +0 -542
- package/docs/guide/filters.md +0 -1314
- package/docs/guide/getting-started.md +0 -204
- package/docs/guide/installation.md +0 -190
- package/docs/guide/partial-templates.md +0 -734
- package/docs/guide/quick-start.md +0 -444
- package/docs/guide/security.md +0 -690
- package/docs/guide/tags.md +0 -1566
- package/docs/guide/template-discovery.md +0 -340
- package/docs/guide/template-inheritance.md +0 -546
- package/docs/guide/what-is-miki-template.md +0 -28
- package/docs/guide/why-miki-template.md +0 -75
- package/docs/index.md +0 -86
- package/docs/integrations/elysia.md +0 -80
- package/docs/integrations/express.md +0 -219
- package/docs/integrations/fastify.md +0 -79
- package/docs/integrations/hono.md +0 -80
- package/docs/integrations/index.md +0 -68
- package/docs/integrations/koa.md +0 -90
- package/docs/integrations/nestjs.md +0 -80
- package/docs/integrations/tsed.md +0 -83
- package/docs/performance.md +0 -74
- package/eslint.config.mjs +0 -42
- package/ex.mjs +0 -36
- package/live-test/integrations/elysia-example.js +0 -16
- package/live-test/integrations/express-example.js +0 -24
- package/live-test/integrations/fastify-example.js +0 -20
- package/live-test/integrations/hono-example.js +0 -16
- package/live-test/integrations/koa-example.js +0 -30
- package/live-test/integrations/nestjs-example.js +0 -25
- package/live-test/integrations/smoke-test.js +0 -166
- package/live-test/integrations/tsed-example.js +0 -23
- package/live-test/package-lock.json +0 -1150
- package/live-test/package.json +0 -13
- package/live-test/packages/product/templates/product/detail.html +0 -7
- package/live-test/server.js +0 -38
- package/live-test/templates/app_templates/detail.html +0 -6
- package/live-test/views/base.html +0 -8
- package/live-test/views/child.html +0 -7
- package/live-test/views/home.html +0 -17
- package/live-test/views/index.html +0 -1
- package/miki-template-extension/.github/workflows/ci.yml +0 -116
- package/miki-template-extension/.vscodeignore +0 -7
- package/miki-template-extension/CHANGELOG.md +0 -99
- package/miki-template-extension/LICENSE +0 -21
- package/miki-template-extension/README.md +0 -273
- package/miki-template-extension/extension.js +0 -1013
- package/miki-template-extension/icon.png +0 -0
- package/miki-template-extension/icon.svg +0 -10
- package/miki-template-extension/miki-template-1.7.1.vsix +0 -0
- package/miki-template-extension/package.json +0 -280
- package/miki-template-extension/snippets/miki-template.json +0 -717
- package/miki-template-extension/syntaxes/language-configuration.json +0 -114
- package/miki-template-extension/syntaxes/miki-template.tmLanguage.json +0 -355
- package/miki-template-extension/tests/grammar-tests.json +0 -162
- package/miki-template-extension/tests/run-grammar-tests.js +0 -82
- package/mkdocs.yml +0 -195
- package/overrides/main.html +0 -26
- package/requirements-docs.txt +0 -2
- package/sample-app/package-lock.json +0 -901
- package/sample-app/package.json +0 -9
- package/sample-app/server.js +0 -14
- package/sample-app/views/index.html +0 -1
- package/scripts/build-vsix.js +0 -129
- package/scripts/build-vsix.ps1 +0 -15
- package/snippets/miki-template.json +0 -177
- package/src/asyncRender.js +0 -21
- package/src/types.d.ts +0 -107
- package/syntaxes/language-configuration.json +0 -26
- package/syntaxes/miki-template.tmLanguage.json +0 -146
- package/tests/asyncRender.test.js +0 -17
- package/tests/base.html +0 -6
- package/tests/child.html +0 -3
- package/tests/context_processors.test.js +0 -13
- package/tests/esm.test.mjs +0 -61
- package/tests/filters.test.js +0 -263
- package/tests/finder-appdirs.test.js +0 -19
- package/tests/finder.test.js +0 -17
- package/tests/fixtures/views/nested/index.html +0 -1
- package/tests/fixtures/views/partial.html +0 -1
- package/tests/fixtures/views/sub/deepfile.html +0 -1
- package/tests/fixtures/views-appdirs/product/site/detail.html +0 -1
- package/tests/include_security.test.js +0 -9
- package/tests/integration/README.md +0 -32
- package/tests/integration/features.test.cjs +0 -1681
- package/tests/integration/features.test.mjs +0 -1697
- package/tests/integration/finder.esm.test.mjs +0 -13
- package/tests/integration/partial-render.test.cjs +0 -13
- package/tests/integration/templates/base.miki +0 -6
- package/tests/integration/templates/child.miki +0 -6
- package/tests/integration/templates/index.html +0 -17
- package/tests/lexer.test.js +0 -45
- package/tests/parser.test.js +0 -57
- package/tests/partial.html +0 -1
- package/tests/partialdef.test.js +0 -79
- package/tests/production_checks.js +0 -57
- package/tests/security.test.js +0 -28
- package/tests/tags.test.js +0 -233
package/API_REFERENCE.md
DELETED
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
# API Reference - miki-template
|
|
2
|
-
|
|
3
|
-
This document provides complete details for the public APIs exported by the **miki-template** engine — a Django-style template engine for Node.js and Express.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Core Exports
|
|
8
|
-
|
|
9
|
-
```javascript
|
|
10
|
-
const {
|
|
11
|
-
compile,
|
|
12
|
-
render,
|
|
13
|
-
asyncRender,
|
|
14
|
-
__express,
|
|
15
|
-
clearCache,
|
|
16
|
-
registerTag,
|
|
17
|
-
registerFilter,
|
|
18
|
-
registerHelper,
|
|
19
|
-
registerContextProcessor,
|
|
20
|
-
SafeString,
|
|
21
|
-
markSafe,
|
|
22
|
-
isSafe,
|
|
23
|
-
escapeHtml
|
|
24
|
-
} = require('miki-template');
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
### `compile(templateStr, options)`
|
|
30
|
-
|
|
31
|
-
Compiles a raw template string into a reusable compiled template object. The compiled template caches its AST internally.
|
|
32
|
-
|
|
33
|
-
**Parameters**:
|
|
34
|
-
- `templateStr` (string): The raw template string to compile.
|
|
35
|
-
- `options` (object): Config parameters:
|
|
36
|
-
- `views` (string|string[]): Directories to search for templates when using `extends` or `include`.
|
|
37
|
-
- `staticUrl` (string): Prefix for the `{% static %}` tag. Defaults to `/static/`.
|
|
38
|
-
- `urlHelper` (function): Custom URL resolver for `{% url %}` tag.
|
|
39
|
-
|
|
40
|
-
**Returns**: An object containing:
|
|
41
|
-
- `render(context)` — Synchronously renders the template.
|
|
42
|
-
- `asyncRender(context)` — Returns a Promise for async rendering.
|
|
43
|
-
- `renderBlock(blockName, context)` — Renders a specific block by name.
|
|
44
|
-
- `renderPartial(partialName, context)` — Renders a defined partial by name.
|
|
45
|
-
|
|
46
|
-
**Example**:
|
|
47
|
-
```javascript
|
|
48
|
-
const { compile } = require('miki-template');
|
|
49
|
-
|
|
50
|
-
const template = compile('Hello {{ name }}!');
|
|
51
|
-
const output = template.render({ name: 'World' });
|
|
52
|
-
console.log(output); // Hello World!
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
### `render(templateStr, context, options)`
|
|
58
|
-
|
|
59
|
-
One-step convenience function that compiles and renders a template.
|
|
60
|
-
|
|
61
|
-
**Parameters**:
|
|
62
|
-
- `templateStr` (string): Raw template string.
|
|
63
|
-
- `context` (object): Variables available to the template.
|
|
64
|
-
- `options` (object): Same as `compile()` options.
|
|
65
|
-
|
|
66
|
-
**Returns**: Rendered HTML string.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
### `asyncRender(templateStr, context, options)`
|
|
71
|
-
|
|
72
|
-
Asynchronous rendering for templates with async helpers or async context processors.
|
|
73
|
-
|
|
74
|
-
**Parameters**: Same as `render()`.
|
|
75
|
-
|
|
76
|
-
**Returns**: `Promise<string>` — resolved rendered HTML.
|
|
77
|
-
|
|
78
|
-
**Example**:
|
|
79
|
-
```javascript
|
|
80
|
-
const { asyncRender } = require('miki-template');
|
|
81
|
-
const html = await asyncRender('Hello {{ name }}!', { name: 'Async' });
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
### `__express(filePath, options, callback)`
|
|
87
|
-
|
|
88
|
-
Express-compatible view engine adapter. Use with `app.engine()`.
|
|
89
|
-
|
|
90
|
-
**Parameters**:
|
|
91
|
-
- `filePath` (string): Absolute path to the template file.
|
|
92
|
-
- `options` (object): Express `res.render()` context (view engine strips `_locals`, `settings`, and other Express internals).
|
|
93
|
-
- `callback` (function): Node.js callback `(err, html)`.
|
|
94
|
-
|
|
95
|
-
**Example**:
|
|
96
|
-
```javascript
|
|
97
|
-
const express = require('express');
|
|
98
|
-
const { __express } = require('miki-template');
|
|
99
|
-
|
|
100
|
-
const app = express();
|
|
101
|
-
app.engine('html', __express);
|
|
102
|
-
app.set('view engine', 'html');
|
|
103
|
-
app.set('views', './views');
|
|
104
|
-
|
|
105
|
-
app.get('/', (req, res) => {
|
|
106
|
-
res.render('home', { title: 'Home Page' });
|
|
107
|
-
});
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Template discovery helpers
|
|
111
|
-
|
|
112
|
-
`miki-template` exposes helpers to discover templates across multiple
|
|
113
|
-
`views` roots and to configure what directory names are considered
|
|
114
|
-
app-style template folders (e.g. `templates` or `app_templates`). These
|
|
115
|
-
are useful for projects that place templates in nested app folders or
|
|
116
|
-
package-level `templates/` directories.
|
|
117
|
-
|
|
118
|
-
#### `findTemplateInViews(name, viewsDirs)`
|
|
119
|
-
|
|
120
|
-
Search for a template by `name` across the provided `viewsDirs` array
|
|
121
|
-
or single string. Performs direct resolution first, then a recursive
|
|
122
|
-
search for bare filenames. Returns the absolute file path or `null`.
|
|
123
|
-
|
|
124
|
-
Example:
|
|
125
|
-
```js
|
|
126
|
-
const found = require('miki-template').findTemplateInViews('detail', ['./views', './templates']);
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
#### `setAppTemplateDirNames(names)` / `getAppTemplateDirNames()`
|
|
130
|
-
|
|
131
|
-
Configure and retrieve the directory names treated as app-style
|
|
132
|
-
template folders when scanning the project tree. The default is
|
|
133
|
-
`['templates']`. Use `setAppTemplateDirNames(['templates','app_templates'])`
|
|
134
|
-
to include additional conventions.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
### `registerTag(name, parserFn)`
|
|
140
|
-
|
|
141
|
-
Registers a custom block tag parser. Must be called **before** compiling templates that use the tag.
|
|
142
|
-
|
|
143
|
-
**Parameters**:
|
|
144
|
-
- `name` (string): Tag identifier word (e.g. `mytag` for `{% mytag %}`).
|
|
145
|
-
- `parserFn` (function): `(tagContent: string, parser: Parser) => ASTNode`. Receives the raw tag content and the parser instance.
|
|
146
|
-
|
|
147
|
-
**Returns**: `undefined`.
|
|
148
|
-
|
|
149
|
-
**Example**:
|
|
150
|
-
```javascript
|
|
151
|
-
const { registerTag } = require('miki-template');
|
|
152
|
-
|
|
153
|
-
registerTag('greet', (tagContent, parser) => {
|
|
154
|
-
const name = tagContent.slice(5).trim(); // strip 'greet'
|
|
155
|
-
return {
|
|
156
|
-
render: (context) => `Hello ${context.get(name) || 'Guest'}!`
|
|
157
|
-
};
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// In template: {% greet user.name %}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
### `registerFilter(name, filterFn)`
|
|
166
|
-
|
|
167
|
-
Registers a custom filter function.
|
|
168
|
-
|
|
169
|
-
**Parameters**:
|
|
170
|
-
- `name` (string): Filter name used after the pipe `|`.
|
|
171
|
-
- `filterFn` (function): `(value: any, arg?: any) => any`. Receives the filtered value and optional argument.
|
|
172
|
-
|
|
173
|
-
**Returns**: `undefined`.
|
|
174
|
-
|
|
175
|
-
**Example**:
|
|
176
|
-
```javascript
|
|
177
|
-
const { registerFilter } = require('miki-template');
|
|
178
|
-
|
|
179
|
-
registerFilter('reverse', (val) => {
|
|
180
|
-
return String(val).split('').reverse().join('');
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// In template: {{ name|reverse }}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
### `registerHelper(name, fn)`
|
|
189
|
-
|
|
190
|
-
Registers a custom block helper tag. The helper receives the **rendered** inner content as a string.
|
|
191
|
-
|
|
192
|
-
**Parameters**:
|
|
193
|
-
- `name` (string): Tag name (e.g. `markdown` creates `{% markdown %}...{% endmarkdown %}`).
|
|
194
|
-
- `fn` (function): `(innerContent: string, context: Context) => string | Promise<string>`.
|
|
195
|
-
|
|
196
|
-
**Returns**: `undefined`.
|
|
197
|
-
|
|
198
|
-
**Example**:
|
|
199
|
-
```javascript
|
|
200
|
-
const { registerHelper } = require('miki-template');
|
|
201
|
-
const markdownIt = require('markdown-it')();
|
|
202
|
-
registerHelper('markdown', (content) => markdownIt.render(content));
|
|
203
|
-
|
|
204
|
-
// In template:
|
|
205
|
-
// {% markdown %}
|
|
206
|
-
// # Hello
|
|
207
|
-
// {% endmarkdown %}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
---
|
|
211
|
-
|
|
212
|
-
### `registerContextProcessor(fn)`
|
|
213
|
-
|
|
214
|
-
Adds a context processor function. Similar to Django's custom context processors.
|
|
215
|
-
|
|
216
|
-
**Parameters**:
|
|
217
|
-
- `fn` (function): `(context: object) => object | undefined`. Receives the render context and returns extra key-value pairs to merge in.
|
|
218
|
-
|
|
219
|
-
**Returns**: `undefined`.
|
|
220
|
-
|
|
221
|
-
**Example**:
|
|
222
|
-
```javascript
|
|
223
|
-
const { registerContextProcessor } = require('miki-template');
|
|
224
|
-
|
|
225
|
-
registerContextProcessor((ctx) => ({
|
|
226
|
-
siteName: 'MySite',
|
|
227
|
-
currentYear: new Date().getFullYear()
|
|
228
|
-
}));
|
|
229
|
-
|
|
230
|
-
// Available in all templates as {{ siteName }} and {{ currentYear }}
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
### `SafeString`
|
|
236
|
-
|
|
237
|
-
Class for values that should **bypass HTML auto-escaping**. Construct directly or use `markSafe()`.
|
|
238
|
-
|
|
239
|
-
**Example**:
|
|
240
|
-
```javascript
|
|
241
|
-
const { SafeString } = require('miki-template');
|
|
242
|
-
|
|
243
|
-
const html = new SafeString('<b>Bold</b>');
|
|
244
|
-
// {{ html }} renders as <b>Bold</b>, NOT <b>Bold</b>
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
---
|
|
248
|
-
|
|
249
|
-
### `markSafe(value)`
|
|
250
|
-
|
|
251
|
-
Wraps any value in a `SafeString`, instructing the engine to skip HTML escaping for that value.
|
|
252
|
-
|
|
253
|
-
**Parameters**:
|
|
254
|
-
- `value` (any): Value to mark as safe.
|
|
255
|
-
|
|
256
|
-
**Returns**: `SafeString`.
|
|
257
|
-
|
|
258
|
-
**Example**:
|
|
259
|
-
```javascript
|
|
260
|
-
const { markSafe } = require('miki-template');
|
|
261
|
-
|
|
262
|
-
const html = markSafe('<script>alert("xss")</script>');
|
|
263
|
-
// {{ html }} outputs the script tag literally (use with caution)
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
|
-
### `isSafe(value)`
|
|
269
|
-
|
|
270
|
-
Checks whether a value is a `SafeString` instance.
|
|
271
|
-
|
|
272
|
-
**Parameters**:
|
|
273
|
-
- `value` (any): Value to check.
|
|
274
|
-
|
|
275
|
-
**Returns**: `boolean`.
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
### `escapeHtml(str)`
|
|
280
|
-
|
|
281
|
-
Programmatically escapes HTML special characters (`<`, `>`, `&`, `"`, `'`).
|
|
282
|
-
|
|
283
|
-
**Parameters**:
|
|
284
|
-
- `str` (string): String to escape.
|
|
285
|
-
|
|
286
|
-
**Returns**: `string`.
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
### `clearCache()`
|
|
291
|
-
|
|
292
|
-
Clears the in-memory AST cache. Useful for development or when templates change at runtime.
|
|
293
|
-
|
|
294
|
-
**Example**:
|
|
295
|
-
```javascript
|
|
296
|
-
const { clearCache } = require('miki-template');
|
|
297
|
-
|
|
298
|
-
app.on('restart', () => clearCache());
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
---
|
|
302
|
-
|
|
303
|
-
## Compiled Template API
|
|
304
|
-
|
|
305
|
-
`compile()` returns an object with these methods:
|
|
306
|
-
|
|
307
|
-
### `compiled.render(context)`
|
|
308
|
-
|
|
309
|
-
Synchronously renders the template with the given context.
|
|
310
|
-
|
|
311
|
-
```javascript
|
|
312
|
-
const compiled = compile('Hello {{ name }}!');
|
|
313
|
-
compiled.render({ name: 'World' }); // "Hello World!"
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### `compiled.asyncRender(context)`
|
|
317
|
-
|
|
318
|
-
Renders asynchronously, awaiting any Promise-returning helpers.
|
|
319
|
-
|
|
320
|
-
```javascript
|
|
321
|
-
const html = await compiled.asyncRender({ name: 'Async' });
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### `compiled.renderBlock(blockName, context)`
|
|
325
|
-
|
|
326
|
-
Renders **only** the named block. Useful for HTMX or AJAX partial responses.
|
|
327
|
-
|
|
328
|
-
```javascript
|
|
329
|
-
// Template: {% extends "base.html" %}
|
|
330
|
-
// {% block content %}Main{% endblock %}
|
|
331
|
-
compiled.renderBlock('content', {}); // "Main"
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### `compiled.renderPartial(partialName, context)`
|
|
335
|
-
|
|
336
|
-
Renders a `{% partialdef %}` block by name.
|
|
337
|
-
|
|
338
|
-
```javascript
|
|
339
|
-
// Template: {% partialdef header %}My Header{% endpartialdef %}
|
|
340
|
-
compiled.renderPartial('header', {}); // "My Header"
|
|
341
|
-
```
|
package/CHANGELOG.md
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## [1.3.4] - 2026-09-05
|
|
4
|
-
### Fixed
|
|
5
|
-
- **Express views path resolution** — normalize `views` entries and ensure miki treats file paths as directories when resolving templates and `#partial` lookups. This fixes `Failed to lookup view "home" in views directory ".../dir"` when `miki-template` is used from a host project's `node_modules` and `views` is passed as a file path.
|
|
6
|
-
|
|
7
|
-
## [1.3.3] - 2026-09-04
|
|
8
|
-
### Fixed
|
|
9
|
-
- **`date` and `time` filters** — multi-character tokens (`yyyy`, `MM`, `dd`, `HH`, `mm`, `ii`, `ss`) now work correctly. Previously `"yyyy-MM-dd"` rendered as `"24242424-JunJun-1515"` because each character was treated as an independent token. The fix uses longest-first token matching and adds backward-compatible single-character aliases (`m`/`d`/`H`/`i`/`s` for Django-style unpadded values).
|
|
10
|
-
|
|
11
|
-
### Performance
|
|
12
|
-
- **Inheritance parent-source cache** — `{% extends %}` no longer re-reads the parent template from disk on every render. A 64-entry LRU cache in `src/cache.js` (`getParentSource` / `hasParentSource`) memoises the parent source. Inheritance rendering improved from ~481 rps to **~2,056 rps** in the stress benchmark (4.3× faster, no functional change).
|
|
13
|
-
|
|
14
|
-
### Tooling
|
|
15
|
-
- **`benchmarks/stress.mjs`** — comprehensive 37-check stress benchmark covering correctness, compile speed, render speed, cache behavior, scale, endurance, partial rendering, async, and concurrency. Run with `node benchmarks/stress.mjs`. Exits with code 1 on any failure.
|
|
16
|
-
- **`eslint.config.mjs`** — added `URL`, `URLSearchParams`, `TextEncoder`, `TextDecoder`, `fetch`, `crypto`, `performance` to the Node 18+ globals list so `no-undef` no longer flags standard Web APIs.
|
|
17
|
-
- Removed dead code flagged by the linter: unused `elifBranches` variable in `parseIfChanged`, unused `extractPluralMappings` function in `i18n.js`. Renamed unused tag-parser `parser` parameters to `_parser` in `lorem` library and `parseLoad`.
|
|
18
|
-
|
|
19
|
-
### Verification
|
|
20
|
-
- `npx eslint src/**/*.js` — 0 errors, 0 warnings
|
|
21
|
-
- `npm test` — 397/397 passing
|
|
22
|
-
- `node benchmarks/stress.mjs` — 37/37 passing
|
|
23
|
-
|
|
24
|
-
## [1.3.1] - 2026-09-03
|
|
25
|
-
### Highlights
|
|
26
|
-
- **One-line Express integration**: `miki.setupExpress(app, { extension: 'html', views: dir })` — wires the view engine, `views` directory, and a `res.render` shim that lets you do `res.render('home#card', ...)` for HTMX-style partial responses. No more boilerplate, no extra middleware.
|
|
27
|
-
- **Render-any-partial-from-string**: `renderPartialFromSource(source, partialName, ctx, opts)` loads a template string and returns only the named `{% partialdef %}` body. This is what powers `res.render('view#partial')` and HTMX responses.
|
|
28
|
-
- **True built-in libraries**: `humanize`, `cache`, and `lorem` are now auto-activated on module load — `{% lorem %}` works without `{% load lorem %}`. Existing libraries now also expose helpers, not just tags.
|
|
29
|
-
- **Comprehensive integration test suite**: 382 tests covering every tag, filter, and feature under both CommonJS and ESM, all running against a **real Express HTTP server** on ephemeral ports.
|
|
30
|
-
|
|
31
|
-
### Added
|
|
32
|
-
- `miki.setupExpress(app, { extension, views, async })` — one-line Express bootstrap. Sets `view engine`, registers the engine, and patches `res.render` to handle `view#partial` selectors. Replaces the need to call `app.engine()`, `app.set('views')`, and `app.set('view engine')` manually.
|
|
33
|
-
- `miki.express()` — factory that returns a view-engine function suitable for `app.engine(...)`. Honors `view#partial` suffixes.
|
|
34
|
-
- `miki.expressPartialRenderer()` — middleware that adds `res.renderPartial(view, locals)`. Useful as a drop-in HTMX helper.
|
|
35
|
-
- `renderPartialFromSource(source, partialName, context, options)` — render a single named partial from a template string. Resolves `extends` chains so partials defined inside `{% block %}` tags are discoverable. Walks the AST and registers every `PartialDefNode` it finds, even when nested inside `{% for %}` or `{% if %}` blocks that won't render during partial lookup.
|
|
36
|
-
- `renderPartialFromFile(filePath, partialName, context, options)` — file-based convenience wrapper.
|
|
37
|
-
- `Context.get(name)` now returns `undefined` for missing keys (was `''`). This lets `default_if_none` distinguish "not provided" from an explicit empty string, matching Django.
|
|
38
|
-
- `escapeHtml(value, force = false)` — added a `force` flag so the `|escape` filter re-escapes even a `SafeString` (Django parity).
|
|
39
|
-
- `Context` constructor now supports `partialDefs` and `options` for cloning the partial registry.
|
|
40
|
-
- New exports: `setupExpress`, `express`, `expressPartialRenderer`, `renderPartialFromFile`, `renderPartialFromSource`, `clearContextProcessors`.
|
|
41
|
-
- ESM surface (`src/esm.mjs`) now exposes all the new helpers, with the same `default` + named import shape.
|
|
42
|
-
- Lorem library now ships a real `{% lorem N method %}` tag, a `lorem` filter, plus helpers. Built-in and auto-activated.
|
|
43
|
-
- `library.activate(name)` now also activates helpers and `registerTag` functions, not just filters.
|
|
44
|
-
|
|
45
|
-
### Changed
|
|
46
|
-
- Context processors now follow Django semantics: **existing context values win** over processor defaults. If you render with `{ user: req.user }` and a processor returns `{ user: 'Guest' }`, the explicit value is preserved.
|
|
47
|
-
- `__express` and `__expressAsync` now detect a `#partial` suffix in the view name and delegate to `renderPartialFromSource` automatically. This makes `app.engine('html', miki.__express)` already HTMX-ready — `setupExpress` just adds convenience.
|
|
48
|
-
- `cache.getCompiled` ignores function-valued and `undefined` options when building cache keys, so passing the same `urlHelper` function to multiple `compile()` calls no longer causes cache misses.
|
|
49
|
-
- Lexer rewritten with brace-depth counting for more reliable `{{ }}` and `{% %}` tokenization in templates with nested braces, escaped braces, and unusual whitespace.
|
|
50
|
-
- Filters now receive the rendering `context` as a final argument, so custom filters can read other context variables (e.g. for locale-aware formatting).
|
|
51
|
-
- `for` and `with` tags fully reworked for the user-reported edge cases:
|
|
52
|
-
- `{% with x=1, y=2 as pair %}` — pair list followed by an alias.
|
|
53
|
-
- `{% with value=expr %}` — single pair (no comma).
|
|
54
|
-
- `{% with x=1, y=2 %}` — pure pair list (no alias).
|
|
55
|
-
- Quoted values containing commas (`{% with a="x,y" %}`) parse correctly.
|
|
56
|
-
- Pair values may be context variables.
|
|
57
|
-
- `partial` now accepts `with` kwargs and overrides context for the partial scope.
|
|
58
|
-
- `include` now supports `file#partial` syntax — the same partial-selector pattern works with `{% include %}` as with `res.render`.
|
|
59
|
-
- `url` tag respects `urlHelper` more cleanly: kwargs (a trailing object literal) are passed as the last argument instead of being conflated with positional args.
|
|
60
|
-
- `static` tag normalizes leading slashes; prefix can be customized.
|
|
61
|
-
- `csrf_token` and `csp_nonce_attr` outputs are properly escaped to prevent attribute injection.
|
|
62
|
-
|
|
63
|
-
### Fixed
|
|
64
|
-
- `with a=x b=y` (multi-pair) was previously treated as a single value/expression. Now correctly binds each pair.
|
|
65
|
-
- `cycle` with `as` form emits nothing but stores the value, matching Django.
|
|
66
|
-
- `block.super` works inside partials that override blocks.
|
|
67
|
-
- `extends` resolves `views` from `options.settings.views` (Express's normal path), `options.views`, or the default.
|
|
68
|
-
- Path traversal protection now applies to `extends` *and* `include`, including `include "file#partial"` form.
|
|
69
|
-
- `if` conditions handle dotted lookup, function auto-call, and missing variables without throwing.
|
|
70
|
-
- `default` vs `default_if_none`: `default` falls back on empty string, `null`, and `undefined`; `default_if_none` only on `null`/`undefined`. Both now match Django exactly.
|
|
71
|
-
- `removetags` filter now accepts multiple tag names.
|
|
72
|
-
- `safe` / `escape` filters correctly re-escape `SafeString` only when forced.
|
|
73
|
-
- `Context.get('a.b.c')` no longer stringifies `undefined` to `''`, fixing `{% if x %}` checks against missing variables.
|
|
74
|
-
- Cache key collisions when passing the same template string with different function-valued options (e.g. `urlHelper`).
|
|
75
|
-
|
|
76
|
-
### Compatibility
|
|
77
|
-
- No breaking changes. All existing public APIs continue to work. New APIs are opt-in.
|
|
78
|
-
|
|
79
|
-
## [1.2.0] - 2026-09-01
|
|
80
|
-
### Added
|
|
81
|
-
- Full **ESM** support via `src/esm.mjs` wrapper and conditional `package.json` exports.
|
|
82
|
-
- **TypeScript** type definitions (`src/types.d.ts`).
|
|
83
|
-
- **Async Express 5+** adapter: `__expressAsync(filePath, options) → Promise<string>`.
|
|
84
|
-
- **i18n**: `trans` tag/filter, `blocktrans`, `language`, plural rules, `registerTranslation`.
|
|
85
|
-
- **Plugin/library system**: `registerLibrary`, `registerLibraryFromPath`, built-ins (`humanize`, `cache`, `lorem`).
|
|
86
|
-
- **`load` tag** now activates registered libraries (no longer a stub).
|
|
87
|
-
- **`widthratio`** tag for proportional width calculations.
|
|
88
|
-
- **`debug`** tag for dumping template context during development.
|
|
89
|
-
- **`regroup`** filter for grouping arrays by attribute.
|
|
90
|
-
- **`strftime`** filter with full `date-fns` format support.
|
|
91
|
-
- **Unclosed tag validation**: throws descriptive errors for missing `endif`/`endfor`/`endwith`.
|
|
92
|
-
- **Filter chaining on string literals**: `{{ "Hello"|lower|capfirst }}` now works.
|
|
93
|
-
- New exports: `getFilter`, `stripExpressContext`, `activateLibrary`.
|
|
94
|
-
|
|
95
|
-
### Fixed
|
|
96
|
-
- `for` loop now supports filter expressions in iterable path (e.g. `items|regroup:"category"`).
|
|
97
|
-
- `Context.reset()` properly clears cycle state and blocks between renders.
|
|
98
|
-
- `__express` strips Express framework keys (`_locals`, `settings`, `cache`) from context.
|
|
99
|
-
- `renderPartial` renders only the named partial, not the full template.
|
|
100
|
-
- `with` tag correctly handles multiple `key=value` assignments and quoted values.
|
|
101
|
-
- `if` tag condition evaluation handles `not`, `and`, `or`, and operator precedence correctly.
|
|
102
|
-
- `forloop.parentloop` correctly propagates for nested loops.
|
|
103
|
-
- `floatformat` default behavior matches Django (1 decimal place).
|
|
104
|
-
- `timesince`/`timeuntil` handle seconds, minutes, hours, days correctly.
|
|
105
|
-
- `pluralize` correctly handles singular vs plural forms.
|
|
106
|
-
- `default` filter treats empty string `''` as falsy like Django.
|
|
107
|
-
- `striptags` correctly removes HTML tags and handles edge cases.
|
|
108
|
-
- Spaceless tag preserves whitespace inside tag attributes correctly.
|
|
109
|
-
|
|
110
|
-
### Changed
|
|
111
|
-
- Condition evaluation rewritten to use shunting-yard algorithm for correct operator precedence.
|
|
112
|
-
- Simplified `for` loop to use `[key, value]` tuples internally for cleaner unpacking.
|
|
113
|
-
- Improved `partialdef` to support both quoted and unquoted partial names.
|
|
114
|
-
- `floatformat` with `-1` argument now removes all decimals.
|
|
115
|
-
|
|
116
|
-
## [1.1.0] - 2026-08-31
|
|
117
|
-
### Added
|
|
118
|
-
- Missing `comment`/`endcomment` tag support for block comments.
|
|
119
|
-
- `firstof` tag to return the first non-falsy value from arguments.
|
|
120
|
-
- `length_is` filter for comparing length to a value.
|
|
121
|
-
- `urlencode`, `escapeuri`, `stringformat`, `cut`, `addslashes`, `removetags` filters for Django parity.
|
|
122
|
-
- `Context.reset()` method for clearing state between renders.
|
|
123
|
-
- `firstof` filter variant for inline first-truthy selection.
|
|
124
|
-
|
|
125
|
-
### Fixed
|
|
126
|
-
- Malformed code in `inheritance.js` with extra closing braces.
|
|
127
|
-
- `__express` was not exported from the module.
|
|
128
|
-
- `__express` now strips Express framework keys (`_locals`, `settings`, etc.) from context.
|
|
129
|
-
- `renderPartial` now properly extracts and renders only the named partial definition.
|
|
130
|
-
- `with` tag now correctly handles multiple `key=value` assignments and quoted values.
|
|
131
|
-
- `if` tag condition evaluation now properly handles `not`, `and`, `or`, and operator precedence.
|
|
132
|
-
- `for` loop now correctly unpacks `key, value` from objects and `item, index` from arrays.
|
|
133
|
-
- `forloop.parentloop` now correctly chains for nested loops.
|
|
134
|
-
- Cycle state (`cycleStates`) now resets per render via `Context.reset()`.
|
|
135
|
-
- Async helpers now work correctly with `asyncRender`.
|
|
136
|
-
- Partial definitions now collected at compile time for proper `renderPartial` support.
|
|
137
|
-
- Path traversal protection added to `extends` tag (previously only on `include`).
|
|
138
|
-
- `floatformat` default behavior now matches Django (1 decimal place).
|
|
139
|
-
- `timesince`/`timeuntil` now handles seconds, minutes, hours, days correctly.
|
|
140
|
-
- `pluralize` now correctly handles singular vs plural forms.
|
|
141
|
-
- `default` filter now treats empty string `''` as falsy like Django.
|
|
142
|
-
- `striptags` now correctly removes HTML tags and handles edge cases.
|
|
143
|
-
- Spaceless tag now preserves whitespace inside tag attributes correctly.
|
|
144
|
-
|
|
145
|
-
### Changed
|
|
146
|
-
- Rewrote condition evaluation to use shunting-yard algorithm for correct operator precedence.
|
|
147
|
-
- Simplified `for` loop to use `[key, value]` tuples internally for cleaner unpacking.
|
|
148
|
-
- Improved `partialdef` to support both quoted and unquoted partial names.
|
|
149
|
-
- `floatformat` with `-1` argument now removes all decimals.
|
|
150
|
-
|
|
151
|
-
## [1.0.0] - 2026-08-29
|
|
152
|
-
### Added
|
|
153
|
-
- Full Django‑style template engine with variables, filters, tags, inheritance, partials, and context processors.
|
|
154
|
-
- Security features: auto‑escaping, `markSafe`, `csrf_token` and `csp_nonce_attr` tags.
|
|
155
|
-
- Extensible API: `registerTag`, `registerFilter`, `markSafe`.
|
|
156
|
-
- Express integration via `__express` adapter.
|
|
157
|
-
- Comprehensive test suite (40 passing tests) and benchmark suite.
|
|
158
|
-
- Detailed documentation hierarchy (`docs/`): overview, installation, usage, tags, filters, partialdef, security, API reference, contribution guide.
|
|
159
|
-
- CI workflow using GitHub Actions.
|
|
160
|
-
- Project scaffolding, linting, and contribution guardrails (`AGENT.md`).
|
|
161
|
-
|
|
162
|
-
### Fixed
|
|
163
|
-
- Auto‑escaping now respects `SafeString` values.
|
|
164
|
-
- Context processors correctly propagate returned context.
|
|
165
|
-
- Fixed tag parsing edge cases in `IfNode` and `PartialDefNode`.
|
|
166
|
-
|
|
167
|
-
### Changed
|
|
168
|
-
- Updated README with npm version and CI badges.
|
|
169
|
-
- Added `CHANGELOG.md` for release notes.
|
|
170
|
-
|
|
171
|
-
[1.2.0]: https://github.com/your-repo/miki-template/releases/tag/v1.2.0
|
|
172
|
-
[1.1.0]: https://github.com/your-repo/miki-template/releases/tag/v1.1.0
|
|
173
|
-
[1.0.0]: https://github.com/your-repo/miki-template/releases/tag/v1.0.0
|
package/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
|
2
|
-
|
|
3
|
-
## Our Pledge
|
|
4
|
-
We pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity, experience level, nationality, personal appearance, race, religion, or sexual orientation.
|
|
5
|
-
|
|
6
|
-
## Our Standards
|
|
7
|
-
Examples of behavior that contributes to creating a positive environment include:
|
|
8
|
-
- Using welcoming and inclusive language.
|
|
9
|
-
- Being respectful of differing viewpoints and experiences.
|
|
10
|
-
- Gracefully accepting constructive criticism.
|
|
11
|
-
- Focusing on what is best for the community.
|
|
12
|
-
- Showing empathy towards other community members.
|
|
13
|
-
|
|
14
|
-
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct.
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Contributing to Django-Style Template Engine
|
|
2
|
-
|
|
3
|
-
Thank you for your interest in contributing! Please follow these guidelines:
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 🛠️ Development Setup
|
|
8
|
-
|
|
9
|
-
1. **Clone the Repository**
|
|
10
|
-
2. **Install Dependencies**:
|
|
11
|
-
```bash
|
|
12
|
-
npm install
|
|
13
|
-
```
|
|
14
|
-
3. **Run the Tests**:
|
|
15
|
-
```bash
|
|
16
|
-
npm test
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 🛑 Guardrails & Standards
|
|
22
|
-
|
|
23
|
-
Before submitting a PR, make sure your code aligns with the strict requirements outlined in [AGENT.md](file:///c:/Users/Coder%20Miki/Desktop/miki-template/AGENT.md):
|
|
24
|
-
- Ensure full parity with Django syntax behavior.
|
|
25
|
-
- Do not use `eval()` for safety.
|
|
26
|
-
- Write corresponding unit tests in `tests/` for all new features or bug fixes.
|
|
27
|
-
- Verify that auto-escaping remains secure by default.
|
package/ROADMAP.md
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Project Roadmap - Django-Style Template Engine
|
|
2
|
-
|
|
3
|
-
Our release and packaging timeline.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 🏁 Phase 1 - Core Delivery (Day 1-2)
|
|
8
|
-
- [x] High-performance tokenizing Lexer.
|
|
9
|
-
- [x] AST parser mapping nested blocks.
|
|
10
|
-
- [x] Context Stack Manager supporting dotted lookup and function calls.
|
|
11
|
-
- [x] HTML Auto-escaping using `he` library and `SafeString` wrappers.
|
|
12
|
-
- [x] Complete suite of built-in filters (25+ filters).
|
|
13
|
-
- [x] Core control flow tags (`if`, `for`, `with`, `cycle`, `autoescape`, `comment`, `verbatim`).
|
|
14
|
-
- [x] Dynamic inheritance (`extends`, `block`, `include` with parameter scope).
|
|
15
|
-
- [x] Express layout adapter (`__express`).
|
|
16
|
-
- [x] Complete test suite verification.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## 🚀 Phase 2 - Advanced Performance & Ecosystem (Next Month)
|
|
21
|
-
- [x] **CI/CD Pipeline** – linting, testing, and automated npm publishing via GitHub Actions.
|
|
22
|
-
- [x] **AST Caching** – cache compiled ASTs for static templates (implemented).
|
|
23
|
-
- [x] **Custom Tag Helpers** – simplify registration of custom block tags (implemented via helpers).
|
|
24
|
-
- [x] **Async Render Options** – support async filters/tags for DB lookups (implemented).
|
|
25
|
-
- [x] **Extended Date Syntax** – integrate `date-fns` for full date formatting parity (implemented).
|
|
26
|
-
- [x] **Advanced Usage Docs** – examples covering partialdef, block rendering, and API (added).
|
|
27
|
-
- [x] **Performance Benchmarks** – baseline measurements and optimization guide (added).
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## 📦 Phase 3 - Ecosystem & Tooling (Q4)
|
|
32
|
-
- [ ] VS Code Extension: Syntax highlighting for `.dtpl` or `.html` Django templates.
|
|
33
|
-
- [ ] Web Playground: An interactive sandbox to experiment with the engine.
|
|
34
|
-
- [ ] CLI Compiler: Render templates from the command line.
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## 📚 Documentation
|
|
39
|
-
- [x] Comprehensive docs in `docs/` covering installation, usage, tags, filters, partialdef, security, and API.
|
|
40
|
-
- [x] Advanced examples and performance guide (added).
|
package/assets/banner.png
DELETED
|
Binary file
|
package/assets/logo.png
DELETED
|
Binary file
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"name": "ejs:small",
|
|
4
|
-
"medianMs": 0.005599999999994054,
|
|
5
|
-
"rps": 178571
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"name": "ejs:medium",
|
|
9
|
-
"medianMs": 0.3426000000000613,
|
|
10
|
-
"rps": 2919
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"name": "ejs:large",
|
|
14
|
-
"medianMs": 4.021499999999833,
|
|
15
|
-
"rps": 249
|
|
16
|
-
}
|
|
17
|
-
]
|
package/benchmarks/ejs.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const ejs = require('ejs');
|
|
2
|
-
const { performance } = require('perf_hooks');
|
|
3
|
-
|
|
4
|
-
const SMALL = `<% items.forEach(item => { %>\n<%= item.toUpperCase() %>:<%= item.length %>\n<% }) %>`;
|
|
5
|
-
const MEDIUM = `<% big_items.forEach(i => { %>\n<% if (i % 2 === 0) { %>Even: <%= i %>\n<% } else { %>Odd: <%= i %>\n<% } }) %>`;
|
|
6
|
-
const LARGE = `<% big_items.forEach(i => { %>\n<% small_items.forEach(j => { %>\n<%= i %>:<%= j %> <%= 'x'.repeat(10) %>\n<% }) }) %>`;
|
|
7
|
-
|
|
8
|
-
const data = {
|
|
9
|
-
items: ['alpha', 'beta', 'gamma', 'delta', 'epsilon'],
|
|
10
|
-
big_items: Array.from({ length: 500 }, (_, i) => i),
|
|
11
|
-
small_items: Array.from({ length: 5 }, (_, j) => j)
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
function bench(name, tpl, data, iterations = 5000) {
|
|
15
|
-
const compiled = ejs.compile(tpl);
|
|
16
|
-
for (let i = 0; i < 20; i++) compiled(data);
|
|
17
|
-
|
|
18
|
-
const times = [];
|
|
19
|
-
for (let i = 0; i < iterations; i++) {
|
|
20
|
-
const t0 = performance.now();
|
|
21
|
-
compiled(data);
|
|
22
|
-
times.push(performance.now() - t0);
|
|
23
|
-
}
|
|
24
|
-
times.sort((a, b) => a - b);
|
|
25
|
-
const median = times[Math.floor(times.length / 2)];
|
|
26
|
-
const rps = Math.round(1000 / median);
|
|
27
|
-
console.log(`${name}: ${median.toFixed(3)} ms/op (~${rps.toLocaleString()} rps)`);
|
|
28
|
-
return { name, medianMs: median, rps };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const results = [];
|
|
32
|
-
results.push(bench('ejs:small', SMALL, data, 10000));
|
|
33
|
-
results.push(bench('ejs:medium', MEDIUM, data, 5000));
|
|
34
|
-
results.push(bench('ejs:large', LARGE, data, 1000));
|
|
35
|
-
|
|
36
|
-
const outPath = require('path').join(__dirname, 'ejs-results.json');
|
|
37
|
-
require('fs').writeFileSync(outPath, JSON.stringify(results, null, 2));
|
|
38
|
-
console.log(`\nResults saved to ${outPath}`);
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"name": "handlebars:small",
|
|
4
|
-
"medianMs": 0.0024000000000086175,
|
|
5
|
-
"rps": 416667
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"name": "handlebars:medium",
|
|
9
|
-
"medianMs": 0.16540000000009059,
|
|
10
|
-
"rps": 6046
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"name": "handlebars:large",
|
|
14
|
-
"medianMs": 1.5188000000000557,
|
|
15
|
-
"rps": 658
|
|
16
|
-
}
|
|
17
|
-
]
|