miki-template 1.2.0 → 1.3.3

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 (60) hide show
  1. package/.github/release-notes/v1.3.1.md +55 -0
  2. package/CHANGELOG.md +72 -0
  3. package/README.md +43 -26
  4. package/assets/banner.png +0 -0
  5. package/benchmarks/stress.mjs +647 -0
  6. package/dir/base.html +23 -0
  7. package/dir/cmpnt.html +11 -0
  8. package/dir/footer.html +3 -0
  9. package/dir/home.html +80 -0
  10. package/dir/navbar.html +9 -0
  11. package/docs/api.md +20 -3
  12. package/docs/filters.md +301 -133
  13. package/docs/partialdef.md +30 -1
  14. package/docs/tags.md +63 -0
  15. package/docs/usage.md +50 -3
  16. package/eslint.config.mjs +9 -1
  17. package/ex.mjs +33 -0
  18. package/miki-template-extension/.github/workflows/ci.yml +116 -0
  19. package/miki-template-extension/.vscodeignore +7 -0
  20. package/miki-template-extension/CHANGELOG.md +99 -0
  21. package/miki-template-extension/README.md +244 -53
  22. package/miki-template-extension/extension.js +1013 -0
  23. package/miki-template-extension/icon.png +0 -0
  24. package/miki-template-extension/miki-template-1.7.1.vsix +0 -0
  25. package/miki-template-extension/package.json +244 -10
  26. package/miki-template-extension/snippets/miki-template.json +612 -72
  27. package/miki-template-extension/syntaxes/language-configuration.json +101 -13
  28. package/miki-template-extension/syntaxes/miki-template.tmLanguage.json +270 -61
  29. package/miki-template-extension/tests/grammar-tests.json +162 -0
  30. package/miki-template-extension/tests/run-grammar-tests.js +82 -0
  31. package/package.json +7 -4
  32. package/scripts/build-vsix.js +129 -0
  33. package/scripts/build-vsix.ps1 +15 -0
  34. package/src/cache.js +41 -2
  35. package/src/context.js +9 -5
  36. package/src/context_processors.js +9 -2
  37. package/src/esm.mjs +12 -0
  38. package/src/filters.js +472 -24
  39. package/src/index.js +571 -85
  40. package/src/lexer.js +76 -54
  41. package/src/libraries.js +134 -3
  42. package/src/parser.js +22 -2
  43. package/src/security.js +4 -2
  44. package/src/tags/control.js +150 -21
  45. package/src/tags/extra.js +154 -0
  46. package/src/tags/i18n.js +49 -23
  47. package/src/tags/inheritance.js +142 -23
  48. package/src/tags/util.js +102 -24
  49. package/tests/esm.test.mjs +37 -2
  50. package/tests/filters.test.js +155 -0
  51. package/tests/integration/README.md +32 -0
  52. package/tests/integration/features.test.cjs +1681 -0
  53. package/tests/integration/features.test.mjs +1697 -0
  54. package/tests/integration/templates/base.miki +6 -0
  55. package/tests/integration/templates/child.miki +6 -0
  56. package/tests/integration/templates/index.html +17 -0
  57. package/tests/parser.test.js +5 -3
  58. package/tests/partialdef.test.js +40 -1
  59. package/tests/tags.test.js +30 -0
  60. package/miki-template-1.2.0.vsix +0 -0
package/docs/tags.md CHANGED
@@ -137,6 +137,30 @@ You can also unpack tuple-like values:
137
137
 
138
138
  ---
139
139
 
140
+ ### `{% set %} / {% endset %}`
141
+
142
+ Assigns a value to a variable for later use in the template. Supports both inline and block forms.
143
+
144
+ **Inline form** — assign a single expression:
145
+
146
+ ```html
147
+ {% set total = price|add:tax %}
148
+ <p>Total: {{ total }}</p>
149
+ ```
150
+
151
+ **Block form** — capture rendered content:
152
+
153
+ ```html
154
+ {% set sidebar %}
155
+ {% include "sidebar.html" with user=user %}
156
+ {% endset %}
157
+ {{ sidebar }}
158
+ ```
159
+
160
+ Variables set with `{% set %}` persist in the current scope and can be used after the tag.
161
+
162
+ ---
163
+
140
164
  ### `{% cycle %}`
141
165
 
142
166
  Outputs one of its arguments for each iteration of a loop.
@@ -184,6 +208,33 @@ With `{% else %}` for a fallback:
184
208
 
185
209
  ---
186
210
 
211
+ ### `{% ifchanged %}...{% endifchanged %}`
212
+
213
+ Renders the body only when the value changes. Useful for detecting changes in loops.
214
+
215
+ ```html
216
+ {% for item in items %}
217
+ {% ifchanged item.category %}
218
+ <h2>{{ item.category }}</h2>
219
+ {% endifchanged %}
220
+ <p>{{ item.name }}</p>
221
+ {% endfor %}
222
+ ```
223
+
224
+ Supports `{% else %}` for when the value does not change:
225
+
226
+ ```html
227
+ {% for item in items %}
228
+ {% ifchanged item.category %}
229
+ {{ item.category }}
230
+ {% else %}
231
+ (same)
232
+ {% endifchanged %}
233
+ {% endfor %}
234
+ ```
235
+
236
+ ---
237
+
187
238
  ## Template Inheritance Tags
188
239
 
189
240
  ### `{% extends %}`
@@ -349,6 +400,18 @@ Loads additional filter libraries (for future extensibility).
349
400
 
350
401
  ---
351
402
 
403
+ ### `{% now "format" %}`
404
+
405
+ Outputs the current date/time formatted with the given pattern. Uses the same format codes as the `date` filter.
406
+
407
+ ```html
408
+ {% now "Y-m-d" %} → "2026-09-03"
409
+ {% now "H:i:s" %} → "14:30:45"
410
+ {% now "F j, Y" %} → "September 3, 2026"
411
+ ```
412
+
413
+ ---
414
+
352
415
  ### `{% spaceless %} / {% endspaceless %}`
353
416
 
354
417
  Removes whitespace between HTML tags.
package/docs/usage.md CHANGED
@@ -407,14 +407,59 @@ const html = await asyncRender(template, { db });
407
407
 
408
408
  ## Express Integration
409
409
 
410
- ### Basic Setup
410
+ ### One-Line Setup (recommended)
411
+
412
+ `miki.setupExpress(app, opts)` wires the view engine, the `views` directory, and a `res.render` shim that makes `res.render('view#partial', ...)` return just the named `{% partialdef %}` body — perfect for HTMX.
411
413
 
412
414
  ```javascript
413
415
  const express = require('express');
414
- const { __express } = require('miki-template');
416
+ const miki = require('miki-template');
415
417
 
416
418
  const app = express();
417
419
 
420
+ // That single line: registers the engine, sets views dir, enables #partial selectors.
421
+ miki.setupExpress(app, { extension: 'html', views: './views' });
422
+
423
+ // Full-page render
424
+ app.get('/', (req, res) => res.render('home', { user: req.user }));
425
+
426
+ // HTMX partial response — just append `#partialName` to the view name.
427
+ // Internally this calls the {% partialdef card %} body inside views/home.html.
428
+ app.get('/partials/:name', (req, res) =>
429
+ res.render(`home#${req.params.name}`, { user: req.user })
430
+ );
431
+
432
+ app.listen(3000);
433
+ ```
434
+
435
+ Options:
436
+
437
+ | Option | Default | Description |
438
+ |---|---|---|
439
+ | `extension` | `'html'` | File extension for views. Use `'miki'` if you prefer `.miki` files. |
440
+ | `views` | `app.get('views')` | Views directory (passed to `app.set('views', ...)`). |
441
+ | `async` | `false` | Use the async engine (`__expressAsync`). For Express 5 with async helpers. |
442
+
443
+ > The `res.render` shim intercepts **only** view names containing a `#`. Everything else (full pages, `res.render(view, cb)`, callback forms) goes through Express's normal view lookup, so the integration is fully compatible with existing Express middleware.
444
+
445
+ ### Just-the-Middleware Variant
446
+
447
+ If you already have your own `app.engine()` setup and just want partial responses, add the middleware:
448
+
449
+ ```javascript
450
+ const miki = require('miki-template');
451
+ app.use(miki.expressPartialRenderer());
452
+
453
+ app.get('/card', (req, res) => res.renderPartial('home#card', { user: req.user }));
454
+ ```
455
+
456
+ ### Manual Setup (still supported)
457
+
458
+ ```javascript
459
+ const express = require('express');
460
+ const { __express } = require('miki-template');
461
+
462
+ const app = express();
418
463
  app.engine('html', __express);
419
464
  app.set('view engine', 'html');
420
465
  app.set('views', './views');
@@ -432,9 +477,11 @@ app.listen(3000);
432
477
 
433
478
  ### Async Express Views
434
479
 
435
- Express 5+ supports async route handlers natively:
480
+ Express 5+ supports async route handlers natively. Pass `async: true` to `setupExpress`, or use `__expressAsync` directly:
436
481
 
437
482
  ```javascript
483
+ miki.setupExpress(app, { extension: 'html', views: './views', async: true });
484
+
438
485
  app.get('/user/:id', async (req, res) => {
439
486
  const user = await User.findById(req.params.id);
440
487
  if (!user) return res.status(404).send('Not found');
package/eslint.config.mjs CHANGED
@@ -19,7 +19,15 @@ export default [
19
19
  clearInterval: 'readonly',
20
20
  setImmediate: 'readonly',
21
21
  clearImmediate: 'readonly',
22
- global: 'readonly'
22
+ global: 'readonly',
23
+ // Node 18+ standard globals
24
+ URL: 'readonly',
25
+ URLSearchParams: 'readonly',
26
+ TextEncoder: 'readonly',
27
+ TextDecoder: 'readonly',
28
+ fetch: 'readonly',
29
+ crypto: 'readonly',
30
+ performance: 'readonly'
23
31
  }
24
32
  },
25
33
  rules: {
package/ex.mjs ADDED
@@ -0,0 +1,33 @@
1
+ import express from 'express'
2
+ import miki, {__express,registerContextProcessor} from "miki-template"
3
+ import path from 'node:path';
4
+
5
+ const app =express()
6
+ const dir=path.join(process.cwd(),"dir")
7
+
8
+ // app.engine('html', __express);
9
+ // app.set('view engine', 'html');
10
+ // app.set('views', dir);
11
+ miki.setupExpress(app, { extension: 'html', views: dir });
12
+
13
+ registerContextProcessor((cx)=>({
14
+ siteName:"code with miki",
15
+ login:{'name':"miki", 'email':"miki@example.com"}
16
+ }))
17
+ app.get("/",(req,res)=>{
18
+ const users=[
19
+ {'name':"miki", 'email':"miki@example.com"},
20
+ {'name':"miki2", 'email':"miki2@example.com"},
21
+ {'name':"miki3", 'email':"miki3@example.com"}
22
+ ]
23
+ let data=[
24
+ {name:"miki", email:"jack@miki.com",address:"kumba"},
25
+ {name:"luis",email:"luis@miki.com",address:"kumba"}
26
+ ]
27
+ res.render("home",{name:"miki-template context", users:users, data:data})
28
+ // res.send(content)
29
+ })
30
+
31
+ app.listen(3000, () => {
32
+ console.log('Server is running on port 3000 click: http://localhost:3000')
33
+ } )
@@ -0,0 +1,116 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, master ]
6
+ pull_request:
7
+ branches: [ main, master ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ lint:
12
+ name: Lint Extension
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Setup Node.js
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: '20'
22
+
23
+ - name: Install dependencies
24
+ run: npm install
25
+
26
+ - name: Validate package.json
27
+ run: npm run validate
28
+
29
+ - name: Check for required files
30
+ run: |
31
+ echo "Checking required files..."
32
+ for file in package.json extension.js README.md CHANGELOG.md LICENSE; do
33
+ if [ ! -f "$file" ]; then
34
+ echo "Missing required file: $file"
35
+ exit 1
36
+ fi
37
+ done
38
+
39
+ test-grammar:
40
+ name: Test Grammar
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - name: Checkout
44
+ uses: actions/checkout@v4
45
+
46
+ - name: Setup Node.js
47
+ uses: actions/setup-node@v4
48
+ with:
49
+ node-version: '20'
50
+
51
+ - name: Install test dependencies
52
+ run: npm install --save-dev textmate-grammar-test
53
+
54
+ - name: Run grammar tests
55
+ run: npm run test:grammar
56
+
57
+ package:
58
+ name: Package Extension
59
+ runs-on: ubuntu-latest
60
+ needs: [lint, test-grammar]
61
+ steps:
62
+ - name: Checkout
63
+ uses: actions/checkout@v4
64
+
65
+ - name: Setup Node.js
66
+ uses: actions/setup-node@v4
67
+ with:
68
+ node-version: '20'
69
+
70
+ - name: Install dependencies
71
+ run: npm install
72
+
73
+ - name: Package VSIX
74
+ id: package
75
+ run: |
76
+ npx vsce package --no-dependencies
77
+ echo "version=$(node -p \"require('./package.json').version\")" >> $GITHUB_OUTPUT
78
+ echo "vsix=$(ls *.vsix 2>/dev/null | head -1)" >> $GITHUB_OUTPUT
79
+
80
+ - name: Upload VSIX artifact
81
+ uses: actions/upload-artifact@v4
82
+ with:
83
+ name: miki-template-${{ steps.package.outputs.version }}.vsix
84
+ path: ${{ steps.package.outputs.vsix }}
85
+
86
+ - name: List output files
87
+ run: ls -la *.vsix 2>/dev/null || echo "No VSIX files found"
88
+
89
+ publish:
90
+ name: Publish to Marketplace
91
+ runs-on: ubuntu-latest
92
+ needs: [package]
93
+ if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
94
+ steps:
95
+ - name: Checkout
96
+ uses: actions/checkout@v4
97
+
98
+ - name: Download VSIX
99
+ uses: actions/download-artifact@v4
100
+ with:
101
+ name: miki-template-${{ needs.package.outputs.version }}.vsix
102
+
103
+ - name: Publish to VS Code Marketplace
104
+ run: npx vsce publish --no-dependencies
105
+ env:
106
+ VSCE_PAT: ${{ secrets.VSCE_PAT }}
107
+ continue-on-error: true
108
+
109
+ - name: Create Release
110
+ if: success()
111
+ uses: softprops/action-gh-release@v1
112
+ with:
113
+ files: *.vsix
114
+ generate_release_notes: true
115
+ env:
116
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,7 @@
1
+ .github/
2
+ tests/
3
+ *.vsix
4
+ icon.svg
5
+ *.log
6
+ node_modules/
7
+ .DS_Store
@@ -0,0 +1,99 @@
1
+ # Changelog
2
+
3
+ All notable changes to this extension will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.7.1] - 2026-09-03
9
+
10
+ ### Added
11
+
12
+ - **Rename Blocks (F2)**: Rename `{% block name %}` across workspace with F2
13
+ - **Path Completions**: Auto-suggest template files for `{% include %}` and `{% extends %}`
14
+ - **Semantic Token Provider**: Enhanced semantic highlighting with proper token classification
15
+ - **HTML/CSS/JS Embedded Support**: Full syntax highlighting for embedded languages
16
+ - **Emmet Support**: HTML and JavaScript Emmet abbreviations work in templates
17
+ - **CSS in `<style>` tags**: Proper CSS syntax highlighting
18
+ - **JS in `<script>` tags**: Proper JavaScript syntax highlighting
19
+
20
+ ### Fixed
21
+
22
+ - Grammar patterns for proper HTML scope activation
23
+ - Embedded language mappings for CSS and JavaScript
24
+ - Multiple bug fixes and improvements
25
+
26
+ ## [1.7.0] - 2026-09-03
27
+
28
+ ### Added
29
+
30
+ - **Inlay Hints**: Show inline parameter hints for filter arguments
31
+ - **Project-wide Find References**: Find blocks, includes, extends across entire workspace
32
+ - **Smart Tag Selection**: Double-click to select entire `{% block %}` content
33
+ - **Custom Tag/Filters Detection**: Auto-detect from project config files
34
+ - **Template Preview Command**: Preview template syntax in a webview panel
35
+ - **Smart Paste**: Auto-detect HTML paste for potential escaping
36
+ - **Bracket Matching Highlights**: Visual highlight for matching `{% if %}`/`{% endif %}` pairs
37
+ - **Template Variables IntelliSense**: Common variable names (user, request, form, items, etc.)
38
+ - **Performance Debouncing**: Optimized validation and decorations with debounce
39
+ - **Quick Outline Navigation**: `Ctrl+Shift+.` and `Ctrl+Shift+,` to jump between blocks
40
+
41
+ ### New Commands
42
+ - `goToNextBlock` / `goToPrevBlock` - Navigate between blocks
43
+ - `previewTemplate` - Preview template in new tab
44
+ - `showOutline` - Quick outline navigation
45
+ - `findBlockReferences` - Find all block references
46
+
47
+ ### New Settings
48
+ - `enableInlayHints` - Toggle inlay hints
49
+ - `enableBracketHighlight` - Toggle bracket highlighting
50
+ - `enableSmartPaste` - Toggle smart paste
51
+
52
+ ## [1.6.0] - 2026-09-03
53
+
54
+ ### Added
55
+
56
+ - **Color Decorations**: Automatically highlights color values (`#ff0000`, `rgb()`, `rgba()`, `hsl()`, `hsla()`) in templates
57
+ - **Code Actions**: Quick fixes for common issues
58
+ - **Find References**: Find all references to blocks and includes
59
+ - **New Commands**: wrapInBlock, wrapInFor, wrapInIf, addPrettierIgnore
60
+ - **New Settings**: enableColorDecorations, enableCodeActions
61
+
62
+ ### Changed
63
+
64
+ - Improved completion items with argument hints
65
+ - Better validation diagnostics
66
+ - Enhanced outline view with icons
67
+
68
+ ## [1.5.0] - 2026-09-03
69
+
70
+ ### Added
71
+
72
+ - **Go-to-Definition**: Jump to included/extended templates and block definitions
73
+ - **Outline View**: See template structure
74
+ - **forloop.* Completions**: Auto-complete loop variables
75
+ - **Keyboard Shortcut**: `Ctrl+Shift+F` to wrap selection with filter
76
+
77
+ ## [1.4.0] - 2026-09-02
78
+
79
+ ### Added
80
+
81
+ - Dual language support: `miki-template` and `django-html`
82
+ - File associations: `.miki`, `.miki-template`, `.django`, `.dj`
83
+ - Comprehensive filter support (70+ filters)
84
+ - Prettier integration with `prettier-ignore`
85
+
86
+ ## [1.3.0] - 2026-08-15
87
+
88
+ ### Added
89
+
90
+ - Buy Me a Coffee integration
91
+ - Format on save configuration
92
+
93
+ ## [1.2.0] - 2026-06-01
94
+
95
+ ### Added
96
+
97
+ - Initial release
98
+ - Basic syntax highlighting
99
+ - Code snippets