@dogsbay/minja 0.2.0-beta.48

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +603 -0
  3. package/bin/minja.js +1062 -0
  4. package/dist/browser.d.ts +11 -0
  5. package/dist/browser.d.ts.map +1 -0
  6. package/dist/browser.js +10 -0
  7. package/dist/browser.js.map +1 -0
  8. package/dist/cli.d.ts +5 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +97 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/context.d.ts +47 -0
  13. package/dist/context.d.ts.map +1 -0
  14. package/dist/context.js +112 -0
  15. package/dist/context.js.map +1 -0
  16. package/dist/evaluator.d.ts +20 -0
  17. package/dist/evaluator.d.ts.map +1 -0
  18. package/dist/evaluator.js +207 -0
  19. package/dist/evaluator.js.map +1 -0
  20. package/dist/index.d.ts +18 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +17 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/index.umd.js +1026 -0
  25. package/dist/index.umd.js.map +7 -0
  26. package/dist/index.umd.min.js +9 -0
  27. package/dist/index.umd.min.js.map +7 -0
  28. package/dist/loader-fetch.d.ts +8 -0
  29. package/dist/loader-fetch.d.ts.map +1 -0
  30. package/dist/loader-fetch.js +15 -0
  31. package/dist/loader-fetch.js.map +1 -0
  32. package/dist/loader-memory.d.ts +11 -0
  33. package/dist/loader-memory.d.ts.map +1 -0
  34. package/dist/loader-memory.js +36 -0
  35. package/dist/loader-memory.js.map +1 -0
  36. package/dist/loader.d.ts +54 -0
  37. package/dist/loader.d.ts.map +1 -0
  38. package/dist/loader.js +91 -0
  39. package/dist/loader.js.map +1 -0
  40. package/dist/parser.d.ts +12 -0
  41. package/dist/parser.d.ts.map +1 -0
  42. package/dist/parser.js +501 -0
  43. package/dist/parser.js.map +1 -0
  44. package/dist/renderer.d.ts +13 -0
  45. package/dist/renderer.d.ts.map +1 -0
  46. package/dist/renderer.js +415 -0
  47. package/dist/renderer.js.map +1 -0
  48. package/dist/types.d.ts +150 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/dist/types.js +5 -0
  51. package/dist/types.js.map +1 -0
  52. package/package.json +62 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,603 @@
1
+ # minja
2
+
3
+ **Minimal, secure Jinja2/Nunjucks subset for documentation preprocessing**
4
+
5
+ Minja is a template engine designed specifically for documentation and content preprocessing, using standard Jinja2/Nunjucks syntax with **zero arbitrary code execution risk**.
6
+
7
+ ## Features
8
+
9
+ - **Security First**: No `eval()`, no `new Function()`, no arbitrary code execution
10
+ - **Standard Jinja2 Syntax**: Fully compatible with Jinja2/Nunjucks conditionals
11
+ - **Variable Substitution**: Simple `{{ variable }}` syntax
12
+ - **Conditionals**: `{% if %}`, `{% elif %}`, `{% else %}` with safe expression evaluation
13
+ - **Switch Statements**: `{% switch %}` / `{% case %}` for multiple conditions
14
+ - **Nested Includes**: Recursive `{% include "file.md" %}` support
15
+ - **Leveloffset**: `{% leveloffset +1 %}` for shifting heading levels in included content
16
+ - **Variable Scoping**: Global and local variables with dot notation
17
+ - **Modern**: TypeScript, ES modules, works in browsers and Node.js
18
+ - **Small**: ~10KB minified + gzipped
19
+ - **Zero Dependencies**: No runtime dependencies
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install minja
25
+ ```
26
+
27
+ Or install globally to use the CLI:
28
+
29
+ ```bash
30
+ npm install -g minja
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ```typescript
36
+ import { render } from 'minja'
37
+
38
+ const template = `
39
+ {% set product = "MyApp" %}
40
+ {% set version = "1.0" %}
41
+
42
+ # {{ product }} Documentation
43
+
44
+ Version: {{ version }}
45
+
46
+ {% if version >= "1.0" %}
47
+ This is a stable release.
48
+ {% endif %}
49
+
50
+ {% include "common/footer.md" %}
51
+ `
52
+
53
+ const output = await render(template, {
54
+ context: {
55
+ author: 'John Doe'
56
+ }
57
+ })
58
+
59
+ console.log(output)
60
+ ```
61
+
62
+ ## CLI Usage
63
+
64
+ Minja includes a command-line interface for rendering templates from files or stdin.
65
+
66
+ ### Basic Usage
67
+
68
+ ```bash
69
+ # Render a template file
70
+ minja template.md
71
+
72
+ # Render with context from JSON file
73
+ minja template.md --context vars.json
74
+
75
+ # Render with context from YAML file
76
+ minja template.md --context vars.yaml
77
+
78
+ # Render with inline variables
79
+ minja template.md --vars '{"title":"My Doc","version":"1.0"}'
80
+
81
+ # Save output to file
82
+ minja template.md --context vars.json --output result.html
83
+
84
+ # Read from stdin
85
+ cat template.md | minja --vars '{"name":"World"}'
86
+ echo "# {{ title }}" | minja --vars '{"title":"Test"}'
87
+ ```
88
+
89
+ ### CLI Options
90
+
91
+ ```
92
+ Usage: minja [options] [template]
93
+
94
+ Arguments:
95
+ template Template file to render (or read from stdin)
96
+
97
+ Options:
98
+ -V, --version output the version number
99
+ -c, --context <file> Context file (JSON or YAML)
100
+ -o, --output <file> Output file (default: stdout)
101
+ -d, --max-depth <number> Maximum include depth (default: 10)
102
+ -t, --timeout <ms> Rendering timeout in milliseconds (default: 5000)
103
+ -v, --vars <json> Inline context variables as JSON
104
+ -h, --help display help for command
105
+ ```
106
+
107
+ ### Examples
108
+
109
+ **Simple template rendering:**
110
+ ```bash
111
+ minja hello.md --vars '{"name":"World"}'
112
+ ```
113
+
114
+ **With context file:**
115
+ ```bash
116
+ # vars.json
117
+ {
118
+ "product": "MyApp",
119
+ "version": "2.0"
120
+ }
121
+
122
+ # Render
123
+ minja README.md --context vars.json
124
+ ```
125
+
126
+ **Using includes:**
127
+ ```bash
128
+ # document.md includes common/vars.md
129
+ minja document.md --output docs/index.html
130
+ ```
131
+
132
+ **Pipeline usage:**
133
+ ```bash
134
+ # Generate docs from multiple sources
135
+ cat header.md content.md footer.md | minja --context config.yaml > output.html
136
+ ```
137
+
138
+ ## Syntax
139
+
140
+ ### Variable Substitution
141
+
142
+ ```
143
+ {{ variable }}
144
+ {{ object.property }}
145
+ {{ nested.property.value }}
146
+ ```
147
+
148
+ ### Variable Definition
149
+
150
+ ```
151
+ {% set variable = "value" %}
152
+ {% set count = 42 %}
153
+ {% set enabled = true %}
154
+ ```
155
+
156
+ ### Conditionals
157
+
158
+ Basic if statement:
159
+ ```
160
+ {% if condition %}
161
+ Content when true
162
+ {% endif %}
163
+ ```
164
+
165
+ If-else statement:
166
+ ```
167
+ {% if condition %}
168
+ Content when true
169
+ {% else %}
170
+ Content when false
171
+ {% endif %}
172
+ ```
173
+
174
+ If-elif-else statement:
175
+ ```
176
+ {% if platform == "aws" %}
177
+ Amazon Web Services
178
+ {% elif platform == "azure" %}
179
+ Microsoft Azure
180
+ {% elif platform == "gcp" %}
181
+ Google Cloud Platform
182
+ {% else %}
183
+ Unknown platform
184
+ {% endif %}
185
+ ```
186
+
187
+ ### Ifdef/Ifndef (AsciiDoc-style)
188
+
189
+ ```
190
+ {% ifdef variable %}
191
+ Content when variable is defined
192
+ {% endifdef %}
193
+
194
+ {% ifndef variable %}
195
+ Content when variable is not defined
196
+ {% endifndef %}
197
+ ```
198
+
199
+ ### Ifeval (Conditional Expressions)
200
+
201
+ ```
202
+ {% ifeval [version >= "1.0"] %}
203
+ Stable release content
204
+ {% endifeval %}
205
+
206
+ {% ifeval [platform == "linux"] %}
207
+ Linux-specific content
208
+ {% endifeval %}
209
+ ```
210
+
211
+ ### Switch Statements
212
+
213
+ Switch-case for multiple conditions:
214
+ ```
215
+ {% switch platform %}
216
+ {% case "aws" %}
217
+ Amazon Web Services (AWS)
218
+ {% case "azure" %}
219
+ Microsoft Azure
220
+ {% case "gcp" %}
221
+ Google Cloud Platform (GCP)
222
+ {% endswitch %}
223
+ ```
224
+
225
+ Switch statements support:
226
+ - String and numeric case values
227
+ - Expression-based switch values
228
+ - Multiple case blocks
229
+ - Falls through on first match only (no default case)
230
+
231
+ ### Leveloffset (Heading Level Control)
232
+
233
+ Shift markdown heading levels in included content:
234
+
235
+ ```
236
+ {% leveloffset +1 %}
237
+ {% include "chapter.md" %}
238
+ {% endleveloffset %}
239
+ ```
240
+
241
+ **Offset types:**
242
+ - **Absolute**: `{% leveloffset 2 %}` - Sets offset to exact value
243
+ - **Relative**: `{% leveloffset +1 %}` or `{% leveloffset -1 %}` - Adds/subtracts from current
244
+ - **Reset**: `{% leveloffset 0 %}` - No offset
245
+
246
+ **Example:**
247
+
248
+ `chapter.md`:
249
+ ```markdown
250
+ # Chapter Title
251
+ ## Section
252
+ ```
253
+
254
+ With `{% leveloffset +1 %}`:
255
+ ```markdown
256
+ ## Chapter Title
257
+ ### Section
258
+ ```
259
+
260
+ This is perfect for modular documentation where you include the same content at different hierarchical levels. Inspired by AsciiDoc's `leveloffset` attribute.
261
+
262
+ See [Leveloffset documentation](docs/syntax-reference.md#leveloffset-heading-level-control) for detailed usage and examples.
263
+
264
+ ### Includes
265
+
266
+ ```
267
+ {% include "path/to/file.md" %}
268
+ {% include "common/header.md" %}
269
+ ```
270
+
271
+ Includes support:
272
+ - Relative paths
273
+ - Nested includes (with depth limit)
274
+ - URL-based loading (in browsers)
275
+ - Filesystem loading (in Node.js)
276
+
277
+ ### Comments
278
+
279
+ ```
280
+ {# This is a comment and won't appear in output #}
281
+ ```
282
+
283
+ Comments on their own line are automatically stripped along with surrounding whitespace.
284
+
285
+ ### Whitespace Control
286
+
287
+ Minja supports Nunjucks/Jinja2 whitespace control syntax to manage spacing and newlines in your output.
288
+
289
+ #### Basic Syntax
290
+
291
+ - `{%-` - Left strip: removes whitespace before the tag
292
+ - `-%}` - Right strip: removes whitespace after the tag
293
+ - `{%- -%}` - Both: removes whitespace on both sides
294
+
295
+ #### Examples
296
+
297
+ **Without whitespace control:**
298
+ ```markdown
299
+ {% set product = "MyApp" %}
300
+ {% set version = "1.0" %}
301
+ # {{ product }}
302
+ ```
303
+
304
+ Output (note the blank lines from set statements):
305
+ ```
306
+
307
+
308
+ # MyApp
309
+ ```
310
+
311
+ **With whitespace control:**
312
+ ```markdown
313
+ {%- set product = "MyApp" -%}
314
+ {%- set version = "1.0" -%}
315
+ # {{ product }}
316
+ ```
317
+
318
+ Output (clean, no blank lines):
319
+ ```
320
+ # MyApp
321
+ ```
322
+
323
+ **Mixed control:**
324
+ ```markdown
325
+ Line 1
326
+ {%- set var = "value" %}
327
+ Line 2
328
+ ```
329
+
330
+ Output (left strip removes newline before set):
331
+ ```
332
+ Line 1
333
+ Line 2
334
+ ```
335
+
336
+ #### Best Practices
337
+
338
+ For attribute files with many set statements, use `{%- set -%}` to avoid blank lines:
339
+
340
+ `common-attributes.md`:
341
+ ```markdown
342
+ {%- set product_name = "MyProduct" -%}
343
+ {%- set product_version = "1.0" -%}
344
+ {%- set company = "ACME Corp" -%}
345
+ ```
346
+
347
+ This prevents each set statement from adding blank lines to your output.
348
+
349
+ ## API
350
+
351
+ ### `render(template, options)`
352
+
353
+ Render a template string.
354
+
355
+ ```typescript
356
+ async function render(
357
+ template: string,
358
+ options?: RenderOptions
359
+ ): Promise<string>
360
+ ```
361
+
362
+ **Options:**
363
+
364
+ - `loader?: Loader` - File loader for includes (default: `FetchLoader`)
365
+ - `context?: Record<string, unknown>` - Initial variables
366
+ - `maxIncludeDepth?: number` - Maximum include recursion depth (default: 10)
367
+ - `timeout?: number` - Rendering timeout in ms (default: 5000)
368
+
369
+ **Example:**
370
+
371
+ ```typescript
372
+ import { render, FileSystemLoader } from 'minja'
373
+
374
+ const output = await render(template, {
375
+ loader: new FileSystemLoader('/path/to/docs'),
376
+ context: {
377
+ product: 'MyApp',
378
+ version: '2.0'
379
+ },
380
+ maxIncludeDepth: 5,
381
+ timeout: 10000
382
+ })
383
+ ```
384
+
385
+ ### Loaders
386
+
387
+ #### `FetchLoader`
388
+
389
+ For browsers and service workers (uses Fetch API).
390
+
391
+ ```typescript
392
+ import { render, FetchLoader } from 'minja'
393
+
394
+ const output = await render(template, {
395
+ loader: new FetchLoader()
396
+ })
397
+ ```
398
+
399
+ #### `FileSystemLoader`
400
+
401
+ For Node.js (uses `fs.readFile`).
402
+
403
+ ```typescript
404
+ import { render, FileSystemLoader } from 'minja'
405
+
406
+ const loader = new FileSystemLoader('/base/path')
407
+ const output = await render(template, { loader })
408
+ ```
409
+
410
+ #### `MemoryLoader`
411
+
412
+ For testing (stores files in memory).
413
+
414
+ ```typescript
415
+ import { render, MemoryLoader } from 'minja'
416
+
417
+ const loader = new MemoryLoader({
418
+ 'header.md': '# {{ title }}',
419
+ 'footer.md': '© 2026'
420
+ })
421
+
422
+ const output = await render('{% include "header.md" %}', { loader })
423
+ ```
424
+
425
+ ## Security Model
426
+
427
+ Minja is designed to be **secure by default**:
428
+
429
+ ### What's Allowed
430
+
431
+ - Variable substitution
432
+ - Safe comparisons (`==`, `!=`, `<`, `>`, `<=`, `>=`)
433
+ - Logical operators (`and`, `or`, `not`)
434
+ - Simple literals (strings, numbers, booleans, null)
435
+ - Dot notation for object properties
436
+
437
+ ### What's Blocked
438
+
439
+ - ❌ Arbitrary code execution
440
+ - ❌ Function calls (except whitelisted built-ins)
441
+ - ❌ Access to `eval`, `Function`, `require`, `import`
442
+ - ❌ Access to `window`, `process`, `globalThis`
443
+ - ❌ Prototype pollution
444
+ - ❌ Property assignment beyond template variables
445
+
446
+ ### Resource Limits
447
+
448
+ - Maximum include depth (default: 10)
449
+ - Rendering timeout (default: 5000ms)
450
+ - Expression complexity limits
451
+
452
+ ## Use Cases
453
+
454
+ Minja is perfect for:
455
+
456
+ - **Documentation preprocessing**: AsciiDoc-style attribute substitution
457
+ - **Static site generation**: Conditional content based on variables
458
+ - **Multi-variant docs**: Platform-specific or version-specific content
459
+ - **Email templates**: Safe user-data substitution
460
+ - **Configuration files**: Template-driven config generation
461
+
462
+ ## Comparison with Nunjucks/Jinja2
463
+
464
+ | Feature | minja | Nunjucks |
465
+ |---------|-------|----------|
466
+ | Variable substitution | ✅ | ✅ |
467
+ | Conditionals (if/elif/else) | ✅ | ✅ |
468
+ | Switch statements | ✅ | ❌ |
469
+ | Includes | ✅ | ✅ |
470
+ | Security | ✅ No code execution | ❌ Arbitrary code |
471
+ | AsciiDoc-style | ✅ ifdef/ifndef/ifeval | ❌ |
472
+ | Loops | ❌ | ✅ |
473
+ | Filters | ❌ | ✅ |
474
+ | Macros | ❌ | ✅ |
475
+ | Extends/Blocks | ❌ | ✅ |
476
+ | Bundle size | ~10KB | ~50KB+ |
477
+
478
+ ## Examples
479
+
480
+ ### Platform-Specific Documentation
481
+
482
+ Using ifeval:
483
+ ```markdown
484
+ {% set platform = "linux" %}
485
+
486
+ # Installation Guide
487
+
488
+ {% ifeval [platform == "linux"] %}
489
+ Install using your package manager:
490
+ ```bash
491
+ sudo apt install myapp
492
+ ```
493
+ {% endifeval %}
494
+
495
+ {% ifeval [platform == "macos"] %}
496
+ Install using Homebrew:
497
+ ```bash
498
+ brew install myapp
499
+ ```
500
+ {% endifeval %}
501
+ ```
502
+
503
+ Using switch statements:
504
+ ```markdown
505
+ {% set platform = "linux" %}
506
+
507
+ # Installation Guide
508
+
509
+ {% switch platform %}
510
+ {% case "linux" %}
511
+ Install using your package manager:
512
+ ```bash
513
+ sudo apt install myapp
514
+ ```
515
+ {% case "macos" %}
516
+ Install using Homebrew:
517
+ ```bash
518
+ brew install myapp
519
+ ```
520
+ {% case "windows" %}
521
+ Download the installer from our website.
522
+ {% endswitch %}
523
+ ```
524
+
525
+ ### Version-Specific Content
526
+
527
+ ```markdown
528
+ {% set version = "2.0" %}
529
+
530
+ # Features
531
+
532
+ {% ifeval [version >= "2.0"] %}
533
+ ## New in 2.0
534
+ - Feature A
535
+ - Feature B
536
+ {% endifeval %}
537
+
538
+ {% ifeval [version >= "1.0"] %}
539
+ ## Available since 1.0
540
+ - Feature X
541
+ - Feature Y
542
+ {% endifeval %}
543
+ ```
544
+
545
+ ### Common Attributes Pattern (AsciiDoc-style)
546
+
547
+ `common-attributes.md`:
548
+ ```
549
+ {%- set product_name = "MyProduct" -%}
550
+ {%- set product_version = "1.0" -%}
551
+ {%- set company = "ACME Corp" -%}
552
+ ```
553
+
554
+ `document.md`:
555
+ ```
556
+ {% include "common-attributes.md" %}
557
+
558
+ # {{ product_name }} Guide
559
+
560
+ Version {{ product_version }}
561
+
562
+ Welcome to {{ product_name }} by {{ company }}.
563
+ ```
564
+
565
+ **Note:** Use `{%- set -%}` in attribute files to prevent blank lines in the output.
566
+
567
+ ## Documentation
568
+
569
+ For complete documentation, see the [docs/](docs/) directory:
570
+
571
+ - **[Getting Started](docs/getting-started.md)** - Installation and your first template
572
+ - **[Syntax Reference](docs/syntax-reference.md)** - Complete syntax documentation
573
+ - **[AsciiDoc Migration](docs/asciidoc-migration.md)** - Converting from AsciiDoc to Minja
574
+ - **[CLI Usage](docs/cli-usage.md)** - Command-line interface guide
575
+ - **[Examples](docs/examples.md)** - Common patterns and use cases
576
+ - **[API Reference](docs/api-reference.md)** - Programmatic API documentation
577
+ - **[FAQ](docs/faq.md)** - Frequently asked questions
578
+
579
+ ## Development
580
+
581
+ ```bash
582
+ # Install dependencies
583
+ npm install
584
+
585
+ # Build
586
+ npm run build
587
+
588
+ # Test
589
+ npm test
590
+
591
+ # Test with coverage
592
+ npm run test:coverage
593
+
594
+ # Lint
595
+ npm run lint
596
+
597
+ # Format
598
+ npm run format
599
+ ```
600
+
601
+ ## License
602
+
603
+ MIT