miki-template 2.3.0 → 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.
Files changed (160) hide show
  1. package/README.md +17 -5
  2. package/package.json +45 -1
  3. package/.eslintrc.json +0 -16
  4. package/.github/release-notes/v1.3.1.md +0 -55
  5. package/.github/release-notes/v1.3.3.md +0 -77
  6. package/.github/release-notes/v1.3.7.md +0 -20
  7. package/.github/workflows/ci.yml +0 -42
  8. package/.github/workflows/docs.yml +0 -107
  9. package/.github/workflows/release.yml +0 -107
  10. package/AGENT.md +0 -71
  11. package/API_REFERENCE.md +0 -341
  12. package/CHANGELOG.md +0 -173
  13. package/CODE_OF_CONDUCT.md +0 -14
  14. package/CONTRIBUTING.md +0 -27
  15. package/ROADMAP.md +0 -40
  16. package/assets/banner.png +0 -0
  17. package/assets/logo.png +0 -0
  18. package/benchmarks/ejs-results.json +0 -17
  19. package/benchmarks/ejs.js +0 -38
  20. package/benchmarks/handlebars-results.json +0 -17
  21. package/benchmarks/handlebars.js +0 -45
  22. package/benchmarks/miki-results.json +0 -17
  23. package/benchmarks/miki.js +0 -39
  24. package/benchmarks/pug-results.json +0 -17
  25. package/benchmarks/pug.js +0 -38
  26. package/benchmarks/report.json +0 -17
  27. package/benchmarks/run.js +0 -81
  28. package/benchmarks/stress.mjs +0 -647
  29. package/benchmarks/templates/large.dtpl +0 -7
  30. package/benchmarks/templates/medium.dtpl +0 -3
  31. package/benchmarks/templates/small.dtpl +0 -7
  32. package/context/component.md +0 -109
  33. package/context/prd.md +0 -131
  34. package/context/project-structure.md +0 -33
  35. package/dir/base.html +0 -23
  36. package/dir/cmpnt.html +0 -11
  37. package/dir/footer.html +0 -3
  38. package/dir/home.html +0 -80
  39. package/dir/index.html +0 -80
  40. package/dir/navbar.html +0 -9
  41. package/docs/api/async-render.md +0 -170
  42. package/docs/api/cache.md +0 -174
  43. package/docs/api/compile.md +0 -256
  44. package/docs/api/context-processors.md +0 -154
  45. package/docs/api/filters.md +0 -437
  46. package/docs/api/finder.md +0 -188
  47. package/docs/api/helpers.md +0 -106
  48. package/docs/api/i18n.md +0 -314
  49. package/docs/api/index.md +0 -108
  50. package/docs/api/libraries.md +0 -414
  51. package/docs/api/render-partial.md +0 -162
  52. package/docs/api/render.md +0 -184
  53. package/docs/api/security.md +0 -290
  54. package/docs/api/setup-express.md +0 -152
  55. package/docs/api/tags.md +0 -268
  56. package/docs/assets/banner.png +0 -0
  57. package/docs/assets/logo.png +0 -0
  58. package/docs/filter.md +0 -0
  59. package/docs/guide/advanced-usage.md +0 -794
  60. package/docs/guide/async-rendering.md +0 -616
  61. package/docs/guide/context-processors.md +0 -514
  62. package/docs/guide/custom-filters.md +0 -622
  63. package/docs/guide/custom-tags.md +0 -542
  64. package/docs/guide/filters.md +0 -1314
  65. package/docs/guide/getting-started.md +0 -204
  66. package/docs/guide/installation.md +0 -190
  67. package/docs/guide/partial-templates.md +0 -734
  68. package/docs/guide/quick-start.md +0 -444
  69. package/docs/guide/security.md +0 -690
  70. package/docs/guide/tags.md +0 -1566
  71. package/docs/guide/template-discovery.md +0 -340
  72. package/docs/guide/template-inheritance.md +0 -546
  73. package/docs/guide/what-is-miki-template.md +0 -28
  74. package/docs/guide/why-miki-template.md +0 -75
  75. package/docs/index.md +0 -86
  76. package/docs/integrations/elysia.md +0 -80
  77. package/docs/integrations/express.md +0 -219
  78. package/docs/integrations/fastify.md +0 -79
  79. package/docs/integrations/hono.md +0 -80
  80. package/docs/integrations/index.md +0 -68
  81. package/docs/integrations/koa.md +0 -90
  82. package/docs/integrations/nestjs.md +0 -80
  83. package/docs/integrations/tsed.md +0 -83
  84. package/docs/performance.md +0 -74
  85. package/eslint.config.mjs +0 -42
  86. package/ex.mjs +0 -36
  87. package/live-test/integrations/elysia-example.js +0 -16
  88. package/live-test/integrations/express-example.js +0 -24
  89. package/live-test/integrations/fastify-example.js +0 -20
  90. package/live-test/integrations/hono-example.js +0 -16
  91. package/live-test/integrations/koa-example.js +0 -30
  92. package/live-test/integrations/nestjs-example.js +0 -25
  93. package/live-test/integrations/smoke-test.js +0 -166
  94. package/live-test/integrations/tsed-example.js +0 -23
  95. package/live-test/package-lock.json +0 -1150
  96. package/live-test/package.json +0 -13
  97. package/live-test/packages/product/templates/product/detail.html +0 -7
  98. package/live-test/server.js +0 -38
  99. package/live-test/templates/app_templates/detail.html +0 -6
  100. package/live-test/views/base.html +0 -8
  101. package/live-test/views/child.html +0 -7
  102. package/live-test/views/home.html +0 -17
  103. package/live-test/views/index.html +0 -1
  104. package/miki-template-extension/.github/workflows/ci.yml +0 -116
  105. package/miki-template-extension/.vscodeignore +0 -7
  106. package/miki-template-extension/CHANGELOG.md +0 -99
  107. package/miki-template-extension/LICENSE +0 -21
  108. package/miki-template-extension/README.md +0 -273
  109. package/miki-template-extension/extension.js +0 -1013
  110. package/miki-template-extension/icon.png +0 -0
  111. package/miki-template-extension/icon.svg +0 -10
  112. package/miki-template-extension/miki-template-1.7.1.vsix +0 -0
  113. package/miki-template-extension/package.json +0 -280
  114. package/miki-template-extension/snippets/miki-template.json +0 -717
  115. package/miki-template-extension/syntaxes/language-configuration.json +0 -114
  116. package/miki-template-extension/syntaxes/miki-template.tmLanguage.json +0 -355
  117. package/miki-template-extension/tests/grammar-tests.json +0 -162
  118. package/miki-template-extension/tests/run-grammar-tests.js +0 -82
  119. package/mkdocs.yml +0 -195
  120. package/overrides/main.html +0 -26
  121. package/requirements-docs.txt +0 -2
  122. package/sample-app/package-lock.json +0 -901
  123. package/sample-app/package.json +0 -9
  124. package/sample-app/server.js +0 -14
  125. package/sample-app/views/index.html +0 -1
  126. package/scripts/build-vsix.js +0 -129
  127. package/scripts/build-vsix.ps1 +0 -15
  128. package/snippets/miki-template.json +0 -177
  129. package/src/asyncRender.js +0 -21
  130. package/src/types.d.ts +0 -107
  131. package/syntaxes/language-configuration.json +0 -26
  132. package/syntaxes/miki-template.tmLanguage.json +0 -146
  133. package/tests/asyncRender.test.js +0 -17
  134. package/tests/base.html +0 -6
  135. package/tests/child.html +0 -3
  136. package/tests/context_processors.test.js +0 -13
  137. package/tests/esm.test.mjs +0 -61
  138. package/tests/filters.test.js +0 -263
  139. package/tests/finder-appdirs.test.js +0 -19
  140. package/tests/finder.test.js +0 -17
  141. package/tests/fixtures/views/nested/index.html +0 -1
  142. package/tests/fixtures/views/partial.html +0 -1
  143. package/tests/fixtures/views/sub/deepfile.html +0 -1
  144. package/tests/fixtures/views-appdirs/product/site/detail.html +0 -1
  145. package/tests/include_security.test.js +0 -9
  146. package/tests/integration/README.md +0 -32
  147. package/tests/integration/features.test.cjs +0 -1681
  148. package/tests/integration/features.test.mjs +0 -1697
  149. package/tests/integration/finder.esm.test.mjs +0 -13
  150. package/tests/integration/partial-render.test.cjs +0 -13
  151. package/tests/integration/templates/base.miki +0 -6
  152. package/tests/integration/templates/child.miki +0 -6
  153. package/tests/integration/templates/index.html +0 -17
  154. package/tests/lexer.test.js +0 -45
  155. package/tests/parser.test.js +0 -57
  156. package/tests/partial.html +0 -1
  157. package/tests/partialdef.test.js +0 -79
  158. package/tests/production_checks.js +0 -57
  159. package/tests/security.test.js +0 -28
  160. package/tests/tags.test.js +0 -233
package/README.md CHANGED
@@ -1,11 +1,16 @@
1
1
  # miki-template
2
+ ###
2
3
  ![miki-template banner](assets/banner.png)
3
4
  ![npm version](https://img.shields.io/npm/v/miki-template.svg) ![CI](https://github.com/your-repo/miki-template/workflows/ci.yml/badge.svg)
4
5
 
5
6
  **Django-style template magic for Node.js — blazing fast partials, smart template discovery, and zero friction for HTMX.**
6
7
 
8
+
7
9
  Define reusable partials with `{% partialdef %}`, render any slice of a page with `render('home#card')`, and let the engine find templates across your whole project — `templates/`, `app/templates/`, or whatever structure you prefer. No more wrestling with view paths or boilerplate middleware.
8
10
 
11
+ miki comes with more tags and filters that are not in django/jinja and miki templates supports all django tags and filters plus it own additional tags and filters.
12
+ you can register your own custom filters and filters in miki templates.
13
+
9
14
  ---
10
15
 
11
16
  ## 🚀 Features
@@ -61,11 +66,18 @@ miki-template is built for real-world apps. Its compiled-AST engine is especiall
61
66
 
62
67
  **Benchmark: renders per second (higher is better)**
63
68
 
64
- | Template | miki-template | pug | handlebars | ejs |
65
- |------------|---------------|---------|------------|---------|
66
- | Small | ~115k rps | 1.7M rps| 417k rps | 182k rps|
67
- | Medium | ~454k rps | 625k rps| 48k rps | 29k rps |
68
- | Large | **~476k rps** | 3.1k rps| 661 rps | 290 rps |
69
+
70
+ | Template | miki-template | pug | handlebars | ejs |
71
+
72
+ |----------|--------------|-----|------------|-----|
73
+
74
+ | Small | ~1.1M rps | 1.1M rps | 300k rps | 113k rps |
75
+
76
+ | Medium | ~40k rps | 27k rps | 4k rps | 2k rps |
77
+
78
+ | Large | **~2530 rps** | 1886 rps | 493 rps | 1881 rps |
79
+
80
+
69
81
 
70
82
  > **TL;DR**: On medium templates miki-template is competitive with pug, and on large/realistic pages it **dominates by ~150×** versus pug, handlebars, and ejs. That’s where production apps live, and that’s where miki wins.
71
83
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miki-template",
3
- "version": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "description": "Django-Style template engine for Node.js and Express",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -10,6 +10,50 @@
10
10
  "default": "./src/index.js"
11
11
  }
12
12
  },
13
+ "files": [
14
+ "src/index.js",
15
+ "src/esm.mjs",
16
+ "src/lexer.js",
17
+ "src/parser.js",
18
+ "src/context.js",
19
+ "src/context_processors.js",
20
+ "src/filters.js",
21
+ "src/security.js",
22
+ "src/cache.js",
23
+ "src/utils.js",
24
+ "src/codegen.js",
25
+ "src/i18n.js",
26
+ "src/libraries.js",
27
+ "src/tags/helpers.js",
28
+ "src/tags/registry.js",
29
+ "src/tags/control.js",
30
+ "src/tags/inheritance.js",
31
+ "src/tags/util.js",
32
+ "src/tags/i18n.js",
33
+ "src/tags/extra.js"
34
+ ],
35
+ "files": [
36
+ "src/index.js",
37
+ "src/esm.mjs",
38
+ "src/lexer.js",
39
+ "src/parser.js",
40
+ "src/context.js",
41
+ "src/context_processors.js",
42
+ "src/filters.js",
43
+ "src/security.js",
44
+ "src/cache.js",
45
+ "src/utils.js",
46
+ "src/codegen.js",
47
+ "src/i18n.js",
48
+ "src/libraries.js",
49
+ "src/tags/helpers.js",
50
+ "src/tags/registry.js",
51
+ "src/tags/control.js",
52
+ "src/tags/inheritance.js",
53
+ "src/tags/util.js",
54
+ "src/tags/i18n.js",
55
+ "src/tags/extra.js"
56
+ ],
13
57
  "keywords": [
14
58
  "django",
15
59
  "template",
package/.eslintrc.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "env": {
3
- "node": true,
4
- "es2024": true
5
- },
6
- "extends": "eslint:recommended",
7
- "parserOptions": {
8
- "ecmaVersion": "latest",
9
- "sourceType": "module"
10
- },
11
- "rules": {
12
- "no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
13
- "no-console": "off",
14
- "semi": ["error", "always"]
15
- }
16
- }
@@ -1,55 +0,0 @@
1
- # miki-template v1.3.1
2
-
3
- ## Highlights
4
-
5
- - **One-line Express integration**: `miki.setupExpress(app, { extension: 'html', views: dir })` wires the view engine, the views directory, and a `res.render` shim that makes HTMX-style partial responses Just Work.
6
-
7
- ```js
8
- const express = require('express');
9
- const miki = require('miki-template');
10
-
11
- const app = express();
12
- miki.setupExpress(app, { extension: 'html', views: './views' });
13
-
14
- // Full page
15
- app.get('/', (req, res) => res.render('home', { user: req.user }));
16
-
17
- // Partial — just append `#partialName` to the view name
18
- app.get('/partials/:name', (req, res) =>
19
- res.render(`home#${req.params.name}`, { user: req.user })
20
- );
21
- ```
22
-
23
- - **`miki.expressPartialRenderer()` middleware** for drop-in `res.renderPartial(view, locals)` without changing your existing `app.engine()` setup.
24
- - **`miki.express()`** factory for `app.engine('html', miki.express())` — honors `view#partial` selectors.
25
- - **`renderPartialFromSource(source, partialName, ctx, opts)`** and **`renderPartialFromFile(...)`** — render a single named `{% partialdef %}` from a string or file. Walks the AST (and the `extends` chain) to find partials nested inside blocks.
26
- - **`{% include "file.html#partial" with ... %}`** — partial-selector syntax works with `include`, not just `res.render`.
27
- - **Built-in libraries** (`humanize`, `cache`, `lorem`) are now auto-activated on module load. `{% lorem 5 p %}` works without `{% load lorem %}`.
28
-
29
- ## Tag fixes
30
-
31
- - `{% with x=1, y=2 as pair %}` (multi-pair + alias) parses correctly.
32
- - `{% with a=x b=y %}` (multi-pair, no alias) now binds each pair instead of being treated as one expression.
33
- - `{% cycle 'a' 'b' as name %}` now emits nothing but stores the value (Django semantics).
34
- - `{{ block.super }}` works inside partials that override blocks.
35
- - `extends` resolves `views` from `options.settings.views` (Express path), `options.views`, or default.
36
- - Path-traversal protection applies to `extends` *and* `include`, including `include "file#partial"`.
37
- - `default` vs `default_if_none`: `default` falls back on `''`, `null`, and `undefined`; `default_if_none` only on `null`/`undefined` (Django parity).
38
- - `removetags` accepts multiple tag names.
39
- - `Context.get('a.b.c')` returns `undefined` for missing keys (was `''`), so `{% if x %}` and `default_if_none` work correctly.
40
-
41
- ## Test coverage
42
-
43
- **382/382 tests pass.** Added a 190-test integration suite (`tests/integration/`) covering every tag, filter, and feature under both CommonJS and ESM, exercised against a real Express HTTP server on ephemeral ports. The test runner recursively picks up `.test.{cjs,mjs,js}` files.
44
-
45
- ## Docs
46
-
47
- - `README.md` — promoted `miki.setupExpress` to the first listed feature; the Express section leads with the one-liner.
48
- - `docs/usage.md` — full Express section rewritten with the new setup, options table, and middleware variant.
49
- - `docs/api.md` — added rows for the new APIs; updated CJS/ESM import snippets.
50
- - `docs/partialdef.md` — documented `include "file#partial"`, `renderPartialFromSource/File`, and the HTMX-over-HTTP flow.
51
- - `CHANGELOG.md` — full entry for 1.3.1.
52
-
53
- ## Compatibility
54
-
55
- No breaking changes. All existing public APIs continue to work; new APIs are opt-in.
@@ -1,77 +0,0 @@
1
- # miki-template v1.3.3
2
-
3
- ## Highlights
4
-
5
- - **Date/time filter fixed** — `{{ d|date:"yyyy-MM-dd" }}` now returns `"2024-06-15"` instead of `"24242424-JunJun-1515"`. Multi-character tokens (`yyyy`, `MM`, `dd`, `HH`, `mm`, `ii`, `ss`) are matched longest-first; backward-compatible single-character aliases (`m`/`d`/`H`/`i`/`s`) still work for Django-style unpadded values.
6
- - **Inheritance 4× faster** — `{% extends %}` no longer re-reads the parent file from disk on every render. A 64-entry LRU cache in `src/cache.js` memoises the parent source. Inheritance rendering improved from ~481 rps to **~2,056 rps** in the strict benchmark.
7
-
8
- ## Installation
9
-
10
- ```bash
11
- npm install miki-template@1.3.3
12
- ```
13
-
14
- ## Quick start
15
-
16
- ```js
17
- const miki = require('miki-template');
18
- const express = require('express');
19
-
20
- const app = express();
21
- miki.setupExpress(app, { extension: 'html', views: './views' });
22
-
23
- // Full page
24
- app.get('/', (req, res) => res.render('home', { user: req.user }));
25
-
26
- // HTMX partial — just append #partialName
27
- app.get('/partials/:name', (req, res) =>
28
- res.render(`home#${req.params.name}`, { user: req.user })
29
- );
30
-
31
- app.listen(3000);
32
- ```
33
-
34
- ## What's changed
35
-
36
- ### Fixed
37
- - `date` and `time` filters — multi-character tokens render correctly.
38
-
39
- ### Performance
40
- - Inheritance parent-source LRU cache in `src/cache.js` (`getParentSource` / `hasParentSource`). `clearCache()` also clears it.
41
-
42
- ### Tooling
43
- - New `benchmarks/stress.mjs` — 37-check strict benchmark (correctness, compile speed, render speed, cache, scale, endurance, partial rendering, async, concurrency). Run with `node benchmarks/stress.mjs`. Exits with code 1 on any failure.
44
- - `eslint.config.mjs` — added `URL`, `URLSearchParams`, `TextEncoder`, `TextDecoder`, `fetch`, `crypto`, `performance` to the Node 18+ globals list.
45
- - Removed dead code: unused `elifBranches` variable in `parseIfChanged`, unused `extractPluralMappings` function in `i18n.js`.
46
- - Renamed unused tag-parser `parser` parameters to `_parser` in `lorem` library and `parseLoad`.
47
-
48
- ## Verification
49
-
50
- | Check | Result |
51
- |---|---|
52
- | `npx eslint src/**/*.js` | 0 errors, 0 warnings |
53
- | `npm test` | 397/397 passing |
54
- | `node benchmarks/stress.mjs` | 37/37 passing |
55
-
56
- ## Performance (from the stress benchmark)
57
-
58
- | Template | Speed |
59
- |---|---|
60
- | Small (76 B) | **175,439 rps** (0.006 ms) |
61
- | Medium (595 B) | 13,947 rps (0.072 ms) |
62
- | Large (1.6 KB, 6 sections × 12 items) | 2,277 rps (0.439 ms) |
63
- | Inheritance child | 2,056 rps (0.486 ms) |
64
- | Partials (50 entries) | 2,235 rps (0.447 ms) |
65
- | Scale: 50,000 items | 107 ms median |
66
- | Endurance: 100,000 renders | 7.5s total, RSS +0.9 MB |
67
- | Async: 200 concurrent LARGE | 237 ms total |
68
-
69
- ## Compatibility
70
-
71
- No breaking changes. All existing public APIs continue to work; new APIs are opt-in.
72
-
73
- ## Links
74
-
75
- - **Repository**: https://github.com/alainmiki/miki-template
76
- - **Tag**: https://github.com/alainmiki/miki-template/releases/tag/v1.3.3
77
- - **Previous**: [v1.3.1](https://github.com/alainmiki/miki-template/releases/tag/v1.3.1)
@@ -1,20 +0,0 @@
1
- ## v1.3.7 — Template discovery improvements
2
-
3
- - Add recursive/app-style template discovery so projects can place
4
- templates in nested `templates/` folders (Django-style) and have
5
- them discovered automatically.
6
- - `setupExpress` now expands `app.get('views')` to include nested
7
- directories that contain template files so `res.render('name')`
8
- works for templates located in project-level or package-level
9
- `templates/` directories.
10
- - Expose `findTemplateInViews(name, roots)` helper and
11
- `setAppTemplateDirNames()/getAppTemplateDirNames()` to configure
12
- app-style template folder names.
13
- - Improve `res.render` fallback to use the recursive finder before
14
- throwing Express's "Failed to lookup view" error.
15
- - Update docs and API reference with usage examples and migration
16
- notes.
17
-
18
- CI: runs lint + tests (all passing locally). If you'd like a more
19
- comprehensive changelog, I can expand this with links to issues and
20
- code snippets.
@@ -1,42 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [ main ]
6
- pull_request:
7
- branches: [ main ]
8
- workflow_dispatch:
9
-
10
- jobs:
11
- lint:
12
- runs-on: ubuntu-latest
13
- steps:
14
- - uses: actions/checkout@v4
15
- - name: Setup Node.js
16
- uses: actions/setup-node@v4
17
- with:
18
- node-version: '20'
19
- cache: 'npm'
20
- - run: npm ci
21
- - name: Lint code
22
- run: npx eslint src/**/*.js
23
-
24
- test:
25
- runs-on: ubuntu-latest
26
- needs: lint
27
- strategy:
28
- matrix:
29
- node-version: [18.x, 20.x]
30
- steps:
31
- - uses: actions/checkout@v4
32
- - name: Use Node.js
33
- uses: actions/setup-node@v4
34
- with:
35
- node-version: ${{ matrix.node-version }}
36
- cache: 'npm'
37
- - run: npm ci
38
- - name: Run unit tests
39
- run: npm test
40
- - name: Run integration smoke-test
41
- if: github.event_name == 'workflow_dispatch'
42
- run: node live-test/integrations/smoke-test.js
@@ -1,107 +0,0 @@
1
- name: Deploy Documentation
2
-
3
- on:
4
- push:
5
- branches: [ main ]
6
- pull_request:
7
- branches: [ main ]
8
- workflow_dispatch:
9
-
10
- permissions:
11
- contents: write
12
- pages: write
13
- id-token: write
14
-
15
- concurrency:
16
- group: "pages"
17
- cancel-in-progress: false
18
-
19
- jobs:
20
- deploy-docs:
21
- runs-on: ubuntu-latest
22
- steps:
23
- - name: Checkout repository
24
- uses: actions/checkout@v4
25
-
26
- - name: Setup Python
27
- uses: actions/setup-python@v5
28
- with:
29
- python-version: '3.12'
30
- cache: 'pip'
31
- cache-dependency-path: 'requirements-docs.txt'
32
-
33
- - name: Install MkDocs Material with imaging support
34
- run: |
35
- python -m pip install --upgrade pip
36
- pip install -r requirements-docs.txt
37
-
38
- - name: Verify docs build
39
- run: mkdocs build --strict
40
- env:
41
- NO_MKDOCS_2_WARNING: 1
42
-
43
- - name: Deploy docs to GitHub Pages
44
- run: 'mkdocs gh-deploy --force --message "chore: deploy docs to GitHub Pages"'
45
-
46
- - name: Output Pages URL
47
- run: echo "Docs deployed to https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/"
48
-
49
- sync-wiki:
50
- runs-on: ubuntu-latest
51
- needs: deploy-docs
52
- steps:
53
- - name: Checkout repository
54
- uses: actions/checkout@v4
55
- with:
56
- fetch-depth: 0
57
-
58
- - name: Setup Git config
59
- run: |
60
- git config --global user.name "github-actions[bot]"
61
- git config --global user.email "github-actions[bot]@users.noreply.github.com"
62
-
63
- - name: Create wiki clone directory
64
- run: mkdir -p wiki-repo
65
-
66
- - name: Clone wiki repository
67
- run: |
68
- git clone https://github.com/${{ github.repository }}.wiki.git wiki-repo || true
69
-
70
- - name: Sync docs to wiki
71
- if: hashFiles('wiki-repo/.git/config') != ''
72
- run: |
73
- cd wiki-repo
74
-
75
- # Copy all markdown docs preserving directory structure
76
- cp -r ../docs/*.md .
77
- cp -r ../docs/guide/*.md ./guide/ 2>/dev/null || true
78
- cp -r ../docs/api/*.md ./api/ 2>/dev/null || true
79
- cp -r ../docs/integrations/*.md ./integrations/ 2>/dev/null || true
80
-
81
- # Remove index.md if it exists (GitHub wiki uses README.md as home page)
82
- if [ -f index.md ]; then
83
- if [ -f README.md ]; then
84
- rm index.md
85
- else
86
- mv index.md README.md
87
- fi
88
- fi
89
-
90
- # Create Home.md from index.md if README.md doesn't exist
91
- if [ ! -f README.md ] && [ ! -f Home.md ] && [ -f docs/index.md ]; then
92
- cp docs/index.md Home.md
93
- fi
94
-
95
- # Commit and push if there are changes
96
- git add -A
97
- git diff --cached --quiet || {
98
- git commit -m "docs: sync documentation to wiki"
99
- git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.wiki.git master
100
- }
101
-
102
- - name: Wiki initialization hint
103
- if: hashFiles('wiki-repo/.git/config') == ''
104
- run: |
105
- echo "::warning::Wiki repository not found. Enable the wiki in repository settings first."
106
- echo "Go to https://github.com/${{ github.repository }}/settings/wiki and click 'Create the first page'"
107
- continue-on-error: true
@@ -1,107 +0,0 @@
1
- # Release workflow
2
- #
3
- # Fully automatic release pipeline. Triggered when a commit to main matches
4
- # the `chore(release): v*` pattern produced by `npm run release:patch|minor|major`.
5
- #
6
- # Flow:
7
- # 1. Detect the new version in package.json.
8
- # 2. Lint + test + stress benchmark (must pass before continuing).
9
- # 3. Create an annotated git tag v<version> and push it.
10
- # 4. Create a GitHub Release with notes from .github/release-notes/v<version>.md
11
- # (or a generic message if the file is missing).
12
- # 5. Publish the package to npm using the NPM_TOKEN secret.
13
- #
14
- # Local usage:
15
- # npm run release:patch # 1.3.3 → 1.3.4
16
- # npm run release:minor # 1.3.3 → 1.4.0
17
- # npm run release:major # 1.3.3 → 2.0.0
18
- # That bumps package.json, creates a commit, pushes to main, and the rest
19
- # happens here.
20
-
21
- name: Release
22
-
23
- on:
24
- push:
25
- branches: [main]
26
-
27
- permissions:
28
- contents: write
29
- packages: write
30
-
31
- jobs:
32
- release:
33
- # Only run for the explicit "chore(release):" commits. Any other
34
- # push to main is ignored so contributors can edit package.json
35
- # without accidentally publishing.
36
- if: startsWith(github.event.head_commit.message, 'chore(release):')
37
- runs-on: ubuntu-latest
38
- steps:
39
- - uses: actions/checkout@v4
40
- with:
41
- fetch-depth: 0
42
- token: ${{ secrets.GITHUB_TOKEN }}
43
-
44
- - uses: actions/setup-node@v4
45
- with:
46
- node-version: '20'
47
- registry-url: 'https://registry.npmjs.org'
48
-
49
- - name: Install dependencies
50
- run: npm ci
51
-
52
- - name: Lint
53
- run: npx eslint src/**/*.js
54
-
55
- - name: Test
56
- run: npm test
57
-
58
- - name: Stress benchmark
59
- run: node benchmarks/stress.mjs
60
-
61
- - name: Read package version
62
- id: ver
63
- run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
64
-
65
- - name: Check tag does not already exist
66
- run: |
67
- if git rev-parse "v${{ steps.ver.outputs.version }}" >/dev/null 2>&1; then
68
- echo "::error::Tag v${{ steps.ver.outputs.version }} already exists."
69
- exit 1
70
- fi
71
-
72
- - name: Create and push git tag
73
- run: |
74
- git config user.name "github-actions[bot]"
75
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
76
- git tag -a "v${{ steps.ver.outputs.version }}" -m "v${{ steps.ver.outputs.version }}"
77
- git push origin "v${{ steps.ver.outputs.version }}"
78
-
79
- - name: Build release body
80
- id: notes
81
- env:
82
- NOTES_FILE: .github/release-notes/v${{ steps.ver.outputs.version }}.md
83
- VERSION: ${{ steps.ver.outputs.version }}
84
- run: |
85
- {
86
- echo "body<<EOF_RELEASE"
87
- if [ -f "$NOTES_FILE" ]; then
88
- cat "$NOTES_FILE"
89
- else
90
- echo "## v${VERSION}"
91
- echo ""
92
- echo "See [CHANGELOG.md](../../blob/main/CHANGELOG.md) for details."
93
- fi
94
- echo "EOF_RELEASE"
95
- } >> "$GITHUB_OUTPUT"
96
-
97
- - name: Create GitHub Release
98
- uses: softprops/action-gh-release@v2
99
- with:
100
- tag_name: v${{ steps.ver.outputs.version }}
101
- name: v${{ steps.ver.outputs.version }}
102
- body: ${{ steps.notes.outputs.body }}
103
-
104
- - name: Publish to npm
105
- run: npm publish --access public
106
- env:
107
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/AGENT.md DELETED
@@ -1,71 +0,0 @@
1
- # AGENT.md - Agent Instructions, Guardrails, & Architecture Rules
2
-
3
- This repository implements a Django-Style Template Engine for Node.js/Express. To ensure high code quality, consistent architecture, and full feature parity with Django without guesswork, all AI agents and developers must strictly follow these instructions and guardrails.
4
-
5
- ---
6
-
7
- ## 🎯 Core Objectives
8
- 1. **Full Feature Parity**: Match Django's template engine rules for rendering variables, dotted lookups, built-in tags, filters, and template inheritance.
9
- 2. **Deterministic & Secure**: Escape output by default using a safe-string mechanism.
10
- 3. **No Spaghetti Code**: Maintain a strict separation of Lexer, Parser, Renderer, Context, and Tag/Filter registries.
11
-
12
- ---
13
-
14
- ## ⚠️ Strict Guardrails & Anti-Hallucination Rules
15
-
16
- > [!IMPORTANT]
17
- > **No Guesswork / Assumptions**
18
- > - If a tag or filter's behavior is not clearly defined in [prd.md](file:///c:/Users/Coder%20Miki/Desktop/miki-template/context/prd.md) or Django documentation, **DO NOT guess**.
19
- > - If you notice ambiguities (e.g., how to handle circular extends or nested cycles), raise a question to the user immediately or throw a descriptive compilation error.
20
-
21
- > [!WARNING]
22
- > **No Regex-Based Global Search & Replace**
23
- > - You **must not** implement tags or filters using global regex replacements on the final string. All templates must go through:
24
- > `Lexer (String -> Tokens) -> Parser (Tokens -> AST) -> Renderer (AST + Context -> HTML)`.
25
- > - Direct regex replacement on HTML bypasses nesting, escaping, and blocks, which introduces severe bugs.
26
-
27
- > [!CAUTION]
28
- > **Security Guardrails**
29
- > - All variable output must be HTML-escaped by default.
30
- > - A variable is only safe from escaping if it is marked as a `SafeString` (e.g., using the `safe` filter or internally flagged).
31
- > - Dynamic expression evaluation (such as in `if` tags) **must not** use direct JS `eval()`. Use a safe AST evaluator or sandboxed parser to prevent remote code execution.
32
-
33
- ---
34
-
35
- ## 🧩 Architectural Guidelines
36
-
37
- ### 1. Lexing (`src/lexer.js`)
38
- * Tokens must be generated for three primary types:
39
- - `TEXT`: Plain HTML/text.
40
- - `VAR`: Variables wrapped in `{{ ... }}`.
41
- - `BLOCK`: Structural tags wrapped in `{% ... %}`.
42
- * The Lexer must correctly handle verbatim blocks `{% verbatim %}` and comments `{% comment %}` by suppressing token output or passing raw text tokens.
43
-
44
- ### 2. Parsing (`src/parser.js`)
45
- * The Parser takes a stream of tokens and constructs an AST of nodes.
46
- * Every node must implement a `.render(context)` method (async or sync).
47
- * For tags that have closing tags (e.g., `{% if %}`...`{% endif %}`), the parser must parse nested tokens recursively until the matching close tag is encountered.
48
-
49
- ### 3. Context & Scope Isolation (`src/context.js`)
50
- * Context must support a stack-like structure: `.push()` to create a new scope, and `.pop()` to revert.
51
- * **Variable Lookups**: Support dotted lookups:
52
- - Example: `{{ user.profile.name }}` should search `user` in context, then resolve property `profile`, then property `name`.
53
- - If a resolved value is a function, call it (without arguments, just like Django).
54
- - If a lookup fails, return an empty string `""` by default, unless configured otherwise.
55
-
56
- ### 4. Template Inheritance (`src/tags/inheritance.js`)
57
- * Inheritance works by having a child template load a parent template via `{% extends "parent.html" %}`.
58
- * The child overrides blocks defined as `{% block block_name %}`.
59
- * During render, the parent's AST is evaluated, but block nodes are replaced by the child's corresponding block nodes.
60
- * Support block nesting and the `{{ block.super }}` variable to render parent block content.
61
-
62
- ---
63
-
64
- ## 🛠️ Step-by-Step Task Execution Protocol
65
-
66
- When executing tasks:
67
- 1. **Analyze Requirements**: Check [prd.md](file:///c:/Users/Coder%20Miki/Desktop/miki-template/context/prd.md) and [component.md](file:///c:/Users/Coder%20Miki/Desktop/miki-template/context/component.md).
68
- 2. **Check Existing Tests**: Run current test suite using `npm test` or `node --test` to ensure a green state.
69
- 3. **Write Tests First**: For any new filter, tag, or parser logic, write a corresponding unit test in `tests/` showing the expected template string and its expected output.
70
- 4. **Implement Modular Code**: Put tag handlers in `src/tags/`, filters in `src/filters.js`, and maintain registry isolation.
71
- 5. **Verify**: Ensure the test suite passes, check for escaping vulnerabilities, and check that no scope leaks occur.