binja 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,12 +23,15 @@
23
23
 
24
24
  ## Why binja?
25
25
 
26
- | Feature | binja | Other JS engines |
26
+ | Feature | Binja | Other JS engines |
27
27
  |---------|-----------|------------------|
28
+ | **AOT Compilation** | ✅ 160x faster | ❌ |
28
29
  | Django DTL Compatible | ✅ 100% | ❌ Partial |
29
30
  | Jinja2 Compatible | ✅ Full | ⚠️ Limited |
30
31
  | Template Inheritance | ✅ | ⚠️ |
31
32
  | 50+ Built-in Filters | ✅ | ❌ |
33
+ | Debug Panel | ✅ | ❌ |
34
+ | CLI Tool | ✅ | ⚠️ |
32
35
  | Autoescape by Default | ✅ | ❌ |
33
36
  | TypeScript | ✅ Native | ⚠️ |
34
37
  | Bun Optimized | ✅ | ❌ |
@@ -37,107 +40,32 @@
37
40
 
38
41
  ## Benchmarks
39
42
 
40
- Tested on MacBook Pro M2, Bun 1.1.x, rendering 1000 iterations.
43
+ Tested on Mac Studio M1 Max, Bun 1.3.5, 10,000 iterations.
41
44
 
42
- ### Simple Template
43
- ```
44
- {{ name }} - {{ title|upper }}
45
- ```
46
-
47
- | Engine | Ops/sec | Relative |
48
- |--------|---------|----------|
49
- | **binja** | **142,857** | **1.0x** |
50
- | Nunjucks | 45,662 | 3.1x slower |
51
- | EJS | 38,461 | 3.7x slower |
52
- | Handlebars | 52,631 | 2.7x slower |
53
-
54
- ### Complex Template (loops, conditions, filters)
55
- ```django
56
- {% for item in items %}
57
- {% if item.active %}
58
- {{ item.name|title }} - ${{ item.price|floatformat:2 }}
59
- {% endif %}
60
- {% endfor %}
61
- ```
45
+ ### Two Rendering Modes
62
46
 
63
- | Engine | Ops/sec | Relative |
64
- |--------|---------|----------|
65
- | **binja** | **28,571** | **1.0x** |
66
- | Nunjucks | 8,928 | 3.2x slower |
67
- | EJS | 12,500 | 2.3x slower |
68
- | Handlebars | 15,384 | 1.9x slower |
47
+ | Mode | Function | Best For | vs Nunjucks |
48
+ |------|----------|----------|-------------|
49
+ | **Runtime** | `render()` | Development | **3.7x faster** |
50
+ | **AOT** | `compile()` | Production | **160x faster** |
69
51
 
70
- ### Template Inheritance
71
- ```django
72
- {% extends "base.html" %}
73
- {% block content %}...{% endblock %}
74
- ```
52
+ ### Performance Comparison
75
53
 
76
- | Engine | Ops/sec | Relative |
77
- |--------|---------|----------|
78
- | **binja** | **18,518** | **1.0x** |
79
- | Nunjucks | 6,250 | 3.0x slower |
80
- | EJS | N/A | Not supported |
81
- | Handlebars | N/A | Not supported |
82
-
83
- ### Memory Usage
84
-
85
- | Engine | Heap (MB) | RSS (MB) |
86
- |--------|-----------|----------|
87
- | **binja** | **12.4** | **45.2** |
88
- | Nunjucks | 28.6 | 89.4 |
89
- | EJS | 18.2 | 62.1 |
54
+ | Benchmark | Nunjucks | binja Runtime | binja AOT |
55
+ |-----------|----------|---------------|-----------|
56
+ | Simple Template | 95K ops/s | 290K ops/s | **14.3M ops/s** |
57
+ | Complex Template | 28K ops/s | 103K ops/s | **1.07M ops/s** |
58
+ | Nested Loops | 27K ops/s | 130K ops/s | **1.75M ops/s** |
59
+ | HTML Escaping | 65K ops/s | 241K ops/s | **2.23M ops/s** |
60
+ | Conditionals | 27K ops/s | 126K ops/s | **22.8M ops/s** |
61
+ | Large Dataset (100 items) | 21K ops/s | 36K ops/s | **202K ops/s** |
90
62
 
91
63
  ### Run Benchmarks
92
64
 
93
65
  ```bash
94
- bun run benchmark
95
- ```
96
-
97
- <details>
98
- <summary>📊 Full Benchmark Code</summary>
99
-
100
- ```typescript
101
- import { Environment } from 'binja'
102
-
103
- const env = new Environment()
104
- const iterations = 1000
105
-
106
- // Simple benchmark
107
- const simpleTemplate = '{{ name }} - {{ title|upper }}'
108
- const simpleContext = { name: 'John', title: 'hello world' }
109
-
110
- console.time('Simple Template')
111
- for (let i = 0; i < iterations; i++) {
112
- await env.renderString(simpleTemplate, simpleContext)
113
- }
114
- console.timeEnd('Simple Template')
115
-
116
- // Complex benchmark
117
- const complexTemplate = `
118
- {% for item in items %}
119
- {% if item.active %}
120
- {{ item.name|title }} - ${{ item.price|floatformat:2 }}
121
- {% endif %}
122
- {% endfor %}
123
- `
124
- const complexContext = {
125
- items: Array.from({ length: 50 }, (_, i) => ({
126
- name: `product ${i}`,
127
- price: Math.random() * 100,
128
- active: Math.random() > 0.3
129
- }))
130
- }
131
-
132
- console.time('Complex Template')
133
- for (let i = 0; i < iterations; i++) {
134
- await env.renderString(complexTemplate, complexContext)
135
- }
136
- console.timeEnd('Complex Template')
66
+ bun run full-benchmark.ts
137
67
  ```
138
68
 
139
- </details>
140
-
141
69
  ---
142
70
 
143
71
  ## Installation
@@ -181,6 +109,37 @@ const html = await env.render('pages/home.html', {
181
109
  })
182
110
  ```
183
111
 
112
+ ### AOT Compilation (Maximum Performance)
113
+
114
+ For production, use `compile()` for **160x faster** rendering:
115
+
116
+ ```typescript
117
+ import { compile } from 'binja'
118
+
119
+ // Compile once at startup
120
+ const renderUser = compile('<h1>{{ name|upper }}</h1>')
121
+
122
+ // Use many times (sync, extremely fast!)
123
+ const html = renderUser({ name: 'john' })
124
+ // Output: <h1>JOHN</h1>
125
+ ```
126
+
127
+ Production example:
128
+
129
+ ```typescript
130
+ import { compile } from 'binja'
131
+
132
+ // Pre-compile all templates at server startup
133
+ const templates = {
134
+ home: compile(await Bun.file('./views/home.html').text()),
135
+ user: compile(await Bun.file('./views/user.html').text()),
136
+ }
137
+
138
+ // Rendering is now synchronous and extremely fast
139
+ app.get('/', () => templates.home({ title: 'Welcome' }))
140
+ app.get('/user/:id', ({ params }) => templates.user({ id: params.id }))
141
+ ```
142
+
184
143
  ---
185
144
 
186
145
  ## Features
@@ -351,6 +310,43 @@ const html = await env.render('pages/home.html', {
351
310
 
352
311
  ---
353
312
 
313
+ ## Tests (is operator)
314
+
315
+ Tests check values using the `is` operator (Jinja2 syntax):
316
+
317
+ ```django
318
+ {% if value is defined %}...{% endif %}
319
+ {% if num is even %}...{% endif %}
320
+ {% if num is divisibleby(3) %}...{% endif %}
321
+ {% if items is empty %}...{% endif %}
322
+ ```
323
+
324
+ ### Built-in Tests
325
+
326
+ | Test | Description |
327
+ |------|-------------|
328
+ | `divisibleby(n)` | Divisible by n |
329
+ | `even` / `odd` | Even/odd integer |
330
+ | `number` / `integer` / `float` | Type checks |
331
+ | `defined` / `undefined` | Variable exists |
332
+ | `none` | Is null |
333
+ | `empty` | Empty array/string/object |
334
+ | `truthy` / `falsy` | Truthiness checks |
335
+ | `string` / `mapping` / `iterable` | Type checks |
336
+ | `gt(n)` / `lt(n)` / `ge(n)` / `le(n)` | Comparisons |
337
+ | `eq(v)` / `ne(v)` / `sameas(v)` | Equality |
338
+ | `upper` / `lower` | String case checks |
339
+
340
+ ```typescript
341
+ import { builtinTests } from 'binja'
342
+
343
+ // All 30+ built-in tests
344
+ console.log(Object.keys(builtinTests))
345
+ // ['divisibleby', 'even', 'odd', 'number', 'integer', ...]
346
+ ```
347
+
348
+ ---
349
+
354
350
  ## Django Compatibility
355
351
 
356
352
  binja is designed to be a drop-in replacement for Django templates:
@@ -408,6 +404,90 @@ const env = new Environment({
408
404
 
409
405
  ---
410
406
 
407
+ ## Debug Panel
408
+
409
+ Binja includes a professional debug panel for development, similar to Django Debug Toolbar:
410
+
411
+ ```typescript
412
+ const env = new Environment({
413
+ templates: './templates',
414
+ debug: true, // Enable debug panel
415
+ debugOptions: {
416
+ dark: true,
417
+ position: 'bottom-right',
418
+ },
419
+ })
420
+
421
+ // Debug panel is automatically injected into HTML responses
422
+ const html = await env.render('page.html', context)
423
+ ```
424
+
425
+ ### Features
426
+
427
+ - **Performance Metrics** - Lexer, Parser, Render timing with visual bars
428
+ - **Template Chain** - See extends/include hierarchy
429
+ - **Context Inspector** - Expandable tree view of all context variables
430
+ - **Filter Usage** - Which filters were used and how many times
431
+ - **Cache Stats** - Hit/miss rates
432
+ - **Warnings** - Optimization suggestions
433
+
434
+ ### Options
435
+
436
+ ```typescript
437
+ debugOptions: {
438
+ dark: true, // Dark/light theme
439
+ collapsed: true, // Start collapsed
440
+ position: 'bottom-right', // Panel position
441
+ width: 420, // Panel width
442
+ }
443
+ ```
444
+
445
+ ---
446
+
447
+ ## CLI Tool
448
+
449
+ Binja includes a CLI for template pre-compilation:
450
+
451
+ ```bash
452
+ # Compile all templates to JavaScript
453
+ binja compile ./templates -o ./dist
454
+
455
+ # Check templates for errors
456
+ binja check ./templates
457
+
458
+ # Watch mode for development
459
+ binja watch ./templates -o ./dist
460
+ ```
461
+
462
+ ### Pre-compiled Templates
463
+
464
+ ```typescript
465
+ // Generated: dist/home.js
466
+ import { render } from './dist/home.js'
467
+
468
+ const html = render({ title: 'Home', items: [...] })
469
+ ```
470
+
471
+ ---
472
+
473
+ ## Raw/Verbatim Tag
474
+
475
+ Output template syntax without processing:
476
+
477
+ ```django
478
+ {% raw %}
479
+ {{ this will not be processed }}
480
+ {% neither will this %}
481
+ {% endraw %}
482
+
483
+ {# Or Django-style #}
484
+ {% verbatim %}
485
+ {{ raw output }}
486
+ {% endverbatim %}
487
+ ```
488
+
489
+ ---
490
+
411
491
  ## Custom Filters
412
492
 
413
493
  ```typescript
@@ -459,31 +539,84 @@ await render('{{ script }}', {
459
539
 
460
540
  ## Performance Tips
461
541
 
462
- 1. **Reuse Environment** - Create once, render many times
463
- 2. **Enable caching** - Templates are cached automatically
464
- 3. **Use Bun** - Native Bun optimizations
542
+ 1. **Use AOT in Production** - `compile()` is 160x faster than Nunjucks
543
+ 2. **Pre-compile at Startup** - Compile templates once, use many times
544
+ 3. **Reuse Environment** - For templates with `{% extends %}`, create once
545
+ 4. **Enable caching** - Templates are cached automatically
465
546
 
466
547
  ```typescript
467
- // Good: Create once
468
- const env = new Environment({ templates: './templates' })
548
+ import { compile } from 'binja'
469
549
 
470
- // Render multiple times
471
- app.get('/', () => env.render('home.html', data))
472
- app.get('/about', () => env.render('about.html', data))
550
+ // Best: AOT compilation for static templates
551
+ const templates = {
552
+ home: compile(await Bun.file('./views/home.html').text()),
553
+ user: compile(await Bun.file('./views/user.html').text()),
554
+ }
555
+
556
+ // Sync rendering, extremely fast
557
+ app.get('/', () => templates.home({ title: 'Home' }))
558
+ app.get('/user/:id', () => templates.user({ id: params.id }))
559
+ ```
560
+
561
+ For templates with inheritance (`{% extends %}`):
562
+
563
+ ```typescript
564
+ import { Environment } from 'binja'
565
+
566
+ // Environment with cache for inherited templates
567
+ const env = new Environment({ templates: './views', cache: true })
568
+
569
+ // Pre-warm cache at startup
570
+ await env.loadTemplate('base.html')
571
+ await env.loadTemplate('home.html')
473
572
  ```
474
573
 
475
574
  ---
476
575
 
477
576
  ## API Reference
478
577
 
479
- ### `render(template, context)`
578
+ ### `render(template, context)` - Runtime Mode
480
579
 
481
- Render a template string with context.
580
+ Render a template string with context (async, easy development).
482
581
 
483
582
  ```typescript
583
+ import { render } from 'binja'
584
+
484
585
  const html = await render('Hello {{ name }}', { name: 'World' })
485
586
  ```
486
587
 
588
+ ### `compile(template, options?)` - AOT Mode
589
+
590
+ Compile a template to an optimized function (sync, **160x faster**).
591
+
592
+ ```typescript
593
+ import { compile } from 'binja'
594
+
595
+ // Compile once
596
+ const renderGreeting = compile('<h1>{{ name|upper }}</h1>')
597
+
598
+ // Use many times (sync!)
599
+ const html = renderGreeting({ name: 'world' }) // <h1>WORLD</h1>
600
+ ```
601
+
602
+ **Supported:** Variables, filters, conditions, loops, set/with, comments.
603
+ **Not supported:** `{% extends %}`, `{% include %}` (use Environment for these).
604
+
605
+ ### `compileToCode(template, options?)`
606
+
607
+ Generate JavaScript code string for build tools.
608
+
609
+ ```typescript
610
+ import { compileToCode } from 'binja'
611
+
612
+ const code = compileToCode('<h1>{{ title }}</h1>', {
613
+ functionName: 'renderHeader'
614
+ })
615
+
616
+ // Save to file for bundling
617
+ await Bun.write('./compiled/header.js', code)
618
+ ```
619
+
487
620
  ### `Environment`
488
621
 
489
622
  Create a configured template environment.
@@ -496,6 +629,7 @@ env.render(name, context) // Render template file
496
629
  env.renderString(str, context) // Render template string
497
630
  env.addFilter(name, fn) // Add custom filter
498
631
  env.addGlobal(name, value) // Add global variable
632
+ env.loadTemplate(name) // Pre-load template (for cache warming)
499
633
  ```
500
634
 
501
635
  ---
@@ -508,8 +642,11 @@ env.addGlobal(name, value) // Add global variable
508
642
  import { Elysia } from 'elysia'
509
643
  import { Environment } from 'binja'
510
644
 
645
+ // Development with debug panel
511
646
  const templates = new Environment({
512
647
  templates: './views',
648
+ debug: Bun.env.NODE_ENV !== 'production',
649
+ debugOptions: { dark: true },
513
650
  globals: {
514
651
  site_name: 'My App',
515
652
  current_year: new Date().getFullYear()
@@ -621,7 +758,13 @@ import { Hono } from 'hono'
621
758
  import { Environment } from 'binja'
622
759
 
623
760
  const app = new Hono()
624
- const templates = new Environment({ templates: './views' })
761
+
762
+ // Development with debug panel
763
+ const templates = new Environment({
764
+ templates: './views',
765
+ debug: process.env.NODE_ENV !== 'production',
766
+ debugOptions: { dark: true, position: 'bottom-right' }
767
+ })
625
768
 
626
769
  app.get('/', async (c) => {
627
770
  const html = await templates.render('index.html', {
@@ -725,4 +868,3 @@ See [LICENSE](./LICENSE) for details.
725
868
  <p align="center">
726
869
  Made with ❤️ for the Bun ecosystem
727
870
  </p>
728
- # binja
package/dist/cli.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * binja CLI - Template pre-compilation tool
4
+ *
5
+ * Usage:
6
+ * binja compile <templates-dir> -o <output-dir>
7
+ * binja compile page.html -o dist/
8
+ * binja watch <templates-dir> -o <output-dir>
9
+ *
10
+ * Examples:
11
+ * binja compile ./templates -o ./dist/templates
12
+ * binja compile ./templates -o ./dist --minify
13
+ * binja compile ./views/home.html -o ./compiled --name renderHome
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG"}