binja 0.5.1 → 0.5.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/README.md CHANGED
@@ -240,109 +240,141 @@ app.get('/user/:id', ({ params }) => templates.user({ id: params.id }))
240
240
 
241
241
  ---
242
242
 
243
- ## Filters
244
-
245
- ### String Filters
246
-
247
- | Filter | Example | Output |
248
- |--------|---------|--------|
249
- | `upper` | `{{ "hello"\|upper }}` | `HELLO` |
250
- | `lower` | `{{ "HELLO"\|lower }}` | `hello` |
251
- | `capitalize` | `{{ "hello"\|capitalize }}` | `Hello` |
252
- | `title` | `{{ "hello world"\|title }}` | `Hello World` |
253
- | `trim` | `{{ " hello "\|trim }}` | `hello` |
254
- | `truncatechars` | `{{ "hello world"\|truncatechars:5 }}` | `he...` |
255
- | `truncatewords` | `{{ "hello world foo"\|truncatewords:2 }}` | `hello world...` |
256
- | `slugify` | `{{ "Hello World!"\|slugify }}` | `hello-world` |
257
- | `striptags` | `{{ "<p>Hello</p>"\|striptags }}` | `Hello` |
258
- | `wordcount` | `{{ "hello world"\|wordcount }}` | `2` |
259
- | `center` | `{{ "hi"\|center:10 }}` | ` hi ` |
260
- | `ljust` | `{{ "hi"\|ljust:10 }}` | `hi ` |
261
- | `rjust` | `{{ "hi"\|rjust:10 }}` | ` hi` |
262
- | `cut` | `{{ "hello"\|cut:"l" }}` | `heo` |
263
- | `addslashes` | `{{ "it's"\|addslashes }}` | `it\'s` |
264
- | `stringformat` | `{{ 5\|stringformat:"03d" }}` | `005` |
265
-
266
- ### Number Filters
267
-
268
- | Filter | Example | Output |
269
- |--------|---------|--------|
270
- | `abs` | `{{ -5\|abs }}` | `5` |
271
- | `add` | `{{ 5\|add:3 }}` | `8` |
272
- | `floatformat` | `{{ 3.14159\|floatformat:2 }}` | `3.14` |
273
- | `filesizeformat` | `{{ 1048576\|filesizeformat }}` | `1.0 MB` |
274
- | `divisibleby` | `{{ 10\|divisibleby:2 }}` | `true` |
275
- | `get_digit` | `{{ 12345\|get_digit:2 }}` | `4` |
276
- | `widthratio` | `{% widthratio value max 100 %}` | Calculated ratio |
277
-
278
- ### List Filters
279
-
280
- | Filter | Example | Output |
281
- |--------|---------|--------|
282
- | `length` | `{{ items\|length }}` | `3` |
283
- | `first` | `{{ items\|first }}` | First item |
284
- | `last` | `{{ items\|last }}` | Last item |
285
- | `join` | `{{ items\|join:", " }}` | `a, b, c` |
286
- | `reverse` | `{{ items\|reverse }}` | Reversed list |
287
- | `sort` | `{{ items\|sort }}` | Sorted list |
288
- | `unique` | `{{ items\|unique }}` | Unique items |
289
- | `slice` | `{{ items\|slice:":2" }}` | First 2 items |
290
- | `batch` | `{{ items\|batch:2 }}` | Grouped by 2 |
291
- | `random` | `{{ items\|random }}` | Random item |
292
-
293
- ### Date Filters
294
-
295
- | Filter | Example | Output |
296
- |--------|---------|--------|
297
- | `date` | `{{ now\|date:"Y-m-d" }}` | `2024-01-15` |
298
- | `time` | `{{ now\|time:"H:i" }}` | `14:30` |
299
- | `timesince` | `{{ past\|timesince }}` | `2 days ago` |
300
- | `timeuntil` | `{{ future\|timeuntil }}` | `in 3 hours` |
243
+ ## Filters (84 Built-in)
244
+
245
+ binja includes **84 built-in filters** covering both Jinja2 and Django Template Language.
246
+
247
+ ### String Filters (26)
248
+
249
+ | Filter | Description | Example |
250
+ |--------|-------------|---------|
251
+ | `upper` | Uppercase | `{{ "hello"\|upper }}` `HELLO` |
252
+ | `lower` | Lowercase | `{{ "HELLO"\|lower }}` `hello` |
253
+ | `capitalize` | First letter uppercase | `{{ "hello"\|capitalize }}` `Hello` |
254
+ | `capfirst` | First char uppercase | `{{ "hello"\|capfirst }}` `Hello` |
255
+ | `title` | Title case | `{{ "hello world"\|title }}` `Hello World` |
256
+ | `trim` | Strip whitespace | `{{ " hi "\|trim }}` `hi` |
257
+ | `striptags` | Remove HTML tags | `{{ "<p>Hi</p>"\|striptags }}` `Hi` |
258
+ | `slugify` | URL-friendly slug | `{{ "Hello World!"\|slugify }}` `hello-world` |
259
+ | `truncatechars` | Truncate to N chars | `{{ "hello"\|truncatechars:3 }}` `hel...` |
260
+ | `truncatewords` | Truncate to N words | `{{ "a b c d"\|truncatewords:2 }}` `a b...` |
261
+ | `truncatechars_html` | Truncate preserving HTML | `{{ "<b>hi</b> world"\|truncatechars_html:5 }}` |
262
+ | `truncatewords_html` | Truncate words in HTML | `{{ "<p>a b c</p>"\|truncatewords_html:2 }}` |
263
+ | `wordcount` | Count words | `{{ "hello world"\|wordcount }}` `2` |
264
+ | `wordwrap` | Wrap at N chars | `{{ text\|wordwrap:40 }}` |
265
+ | `center` | Center in N chars | `{{ "hi"\|center:10 }}` → ` hi ` |
266
+ | `ljust` | Left justify | `{{ "hi"\|ljust:10 }}` → `hi ` |
267
+ | `rjust` | Right justify | `{{ "hi"\|rjust:10 }}` → ` hi` |
268
+ | `cut` | Remove substring | `{{ "hello"\|cut:"l" }}` → `heo` |
269
+ | `replace` | Replace substring | `{{ "hello"\|replace:"l","x" }}` → `hexxo` |
270
+ | `indent` | Indent lines | `{{ text\|indent:4 }}` |
271
+ | `linebreaks` | Newlines to `<p>/<br>` | `{{ text\|linebreaks }}` |
272
+ | `linebreaksbr` | Newlines to `<br>` | `{{ text\|linebreaksbr }}` |
273
+ | `linenumbers` | Add line numbers | `{{ code\|linenumbers }}` |
274
+ | `addslashes` | Escape quotes | `{{ "it's"\|addslashes }}` `it\'s` |
275
+ | `format` | sprintf-style format | `{{ "Hi %s"\|format:name }}` |
276
+ | `stringformat` | Python % format | `{{ 5\|stringformat:"03d" }}` `005` |
277
+
278
+ ### Number Filters (9)
279
+
280
+ | Filter | Description | Example |
281
+ |--------|-------------|---------|
282
+ | `abs` | Absolute value | `{{ -5\|abs }}` `5` |
283
+ | `int` | Convert to integer | `{{ "42"\|int }}` `42` |
284
+ | `float` | Convert to float | `{{ "3.14"\|float }}` `3.14` |
285
+ | `round` | Round number | `{{ 3.7\|round }}` `4` |
286
+ | `add` | Add number | `{{ 5\|add:3 }}` `8` |
287
+ | `divisibleby` | Check divisibility | `{{ 10\|divisibleby:2 }}` `true` |
288
+ | `floatformat` | Format decimal places | `{{ 3.14159\|floatformat:2 }}` `3.14` |
289
+ | `filesizeformat` | Human file size | `{{ 1048576\|filesizeformat }}` `1.0 MB` |
290
+ | `get_digit` | Get Nth digit | `{{ 12345\|get_digit:2 }}` `4` |
291
+
292
+ ### List/Array Filters (22)
293
+
294
+ | Filter | Description | Example |
295
+ |--------|-------------|---------|
296
+ | `length` | List length | `{{ items\|length }}` → `3` |
297
+ | `length_is` | Check length | `{{ items\|length_is:3 }}` `true` |
298
+ | `first` | First item | `{{ items\|first }}` |
299
+ | `last` | Last item | `{{ items\|last }}` |
300
+ | `join` | Join with separator | `{{ items\|join:", " }}` `a, b, c` |
301
+ | `slice` | Slice list | `{{ items\|slice:":2" }}` |
302
+ | `reverse` | Reverse list | `{{ items\|reverse }}` |
303
+ | `sort` | Sort list | `{{ items\|sort }}` |
304
+ | `unique` | Remove duplicates | `{{ items\|unique }}` |
305
+ | `batch` | Group into batches | `{{ items\|batch:2 }}` |
306
+ | `columns` | Split into columns | `{{ items\|columns:3 }}` |
307
+ | `dictsort` | Sort dict by key | `{{ dict\|dictsort }}` |
308
+ | `dictsortreversed` | Sort dict reversed | `{{ dict\|dictsortreversed }}` |
309
+ | `groupby` | Group by attribute | `{{ items\|groupby:"category" }}` |
310
+ | `random` | Random item | `{{ items\|random }}` |
311
+ | `list` | Convert to list | `{{ value\|list }}` |
312
+ | `make_list` | String to char list | `{{ "abc"\|make_list }}` → `['a','b','c']` |
313
+ | `map` | Map attribute | `{{ items\|map:"name" }}` |
314
+ | `select` | Filter by test | `{{ items\|select:"even" }}` |
315
+ | `reject` | Reject by test | `{{ items\|reject:"none" }}` |
316
+ | `selectattr` | Filter by attr test | `{{ items\|selectattr:"active" }}` |
317
+ | `rejectattr` | Reject by attr test | `{{ items\|rejectattr:"hidden" }}` |
318
+
319
+ ### Math Filters (4)
320
+
321
+ | Filter | Description | Example |
322
+ |--------|-------------|---------|
323
+ | `max` | Maximum value | `{{ items\|max }}` |
324
+ | `min` | Minimum value | `{{ items\|min }}` |
325
+ | `sum` | Sum of values | `{{ items\|sum }}` |
326
+ | `attr` | Get attribute | `{{ item\|attr:"name" }}` |
327
+
328
+ ### Date/Time Filters (4)
329
+
330
+ | Filter | Description | Example |
331
+ |--------|-------------|---------|
332
+ | `date` | Format date | `{{ now\|date:"Y-m-d" }}` → `2024-01-15` |
333
+ | `time` | Format time | `{{ now\|time:"H:i" }}` → `14:30` |
334
+ | `timesince` | Time since date | `{{ past\|timesince }}` → `2 days ago` |
335
+ | `timeuntil` | Time until date | `{{ future\|timeuntil }}` → `in 3 hours` |
301
336
 
302
337
  #### Timezone Support
303
338
 
304
- All date/time operations respect the `timezone` option in Environment:
305
-
306
339
  ```typescript
307
340
  const env = new Environment({
308
- timezone: 'Europe/Rome' // All dates will be displayed in Rome timezone
309
- })
310
-
311
- // 2024-06-15 12:00 UTC = 2024-06-15 14:00 Rome (UTC+2)
312
- await env.renderString('{{ date|date:"Y-m-d H:i" }}', {
313
- date: new Date('2024-06-15T12:00:00Z')
341
+ timezone: 'Europe/Rome' // All dates in Rome timezone
314
342
  })
315
- // Output: 2024-06-15 14:00
316
-
317
- // {% now %} tag also uses the configured timezone
318
- await env.renderString('{% now "Y-m-d H:i" %}')
319
- // Output: current date/time in Rome timezone
320
343
  ```
321
344
 
322
- Common timezone values: `UTC`, `Europe/London`, `Europe/Rome`, `Europe/Paris`, `America/New_York`, `America/Los_Angeles`, `Asia/Tokyo`, `Asia/Shanghai`, `Australia/Sydney`
323
-
324
- ### Safety & Encoding
325
-
326
- | Filter | Example | Description |
327
- |--------|---------|-------------|
328
- | `escape` | `{{ html\|escape }}` | HTML escape |
329
- | `safe` | `{{ html\|safe }}` | Mark as safe (no escape) |
330
- | `urlencode` | `{{ url\|urlencode }}` | URL encode |
331
- | `iriencode` | `{{ url\|iriencode }}` | IRI encode (unicode-safe) |
332
- | `json` | `{{ data\|json }}` | JSON stringify |
333
- | `json_script` | `{{ data\|json_script:"id" }}` | Safe JSON in script tag |
334
- | `truncatechars_html` | `{{ html\|truncatechars_html:10 }}` | Truncate preserving HTML |
335
- | `truncatewords_html` | `{{ html\|truncatewords_html:5 }}` | Truncate words in HTML |
336
- | `urlizetrunc` | `{{ text\|urlizetrunc:15 }}` | URLs with truncated display |
337
-
338
- ### Default Values
339
-
340
- | Filter | Example | Output |
341
- |--------|---------|--------|
342
- | `default` | `{{ missing\|default:"N/A" }}` | `N/A` |
343
- | `default_if_none` | `{{ null\|default_if_none:"None" }}` | `None` |
344
- | `yesno` | `{{ true\|yesno:"Yes,No" }}` | `Yes` |
345
- | `pluralize` | `{{ count\|pluralize }}` | `s` or `` |
345
+ ### Safety & Encoding Filters (13)
346
+
347
+ | Filter | Description | Example |
348
+ |--------|-------------|---------|
349
+ | `escape` / `e` | HTML escape | `{{ html\|escape }}` |
350
+ | `forceescape` | Force HTML escape | `{{ html\|forceescape }}` |
351
+ | `safe` | Mark as safe | `{{ html\|safe }}` |
352
+ | `safeseq` | Mark sequence safe | `{{ items\|safeseq }}` |
353
+ | `escapejs` | JS string escape | `{{ text\|escapejs }}` |
354
+ | `urlencode` | URL encode | `{{ url\|urlencode }}` |
355
+ | `iriencode` | IRI encode | `{{ url\|iriencode }}` |
356
+ | `urlize` | URLs to links | `{{ text\|urlize }}` |
357
+ | `urlizetrunc` | URLs to links (truncated) | `{{ text\|urlizetrunc:15 }}` |
358
+ | `json` / `tojson` | JSON stringify | `{{ data\|json }}` |
359
+ | `json_script` | Safe JSON in script | `{{ data\|json_script:"id" }}` |
360
+ | `pprint` | Pretty print | `{{ data\|pprint }}` |
361
+ | `xmlattr` | Dict to XML attrs | `{{ attrs\|xmlattr }}` |
362
+
363
+ ### Default/Conditional Filters (4)
364
+
365
+ | Filter | Description | Example |
366
+ |--------|-------------|---------|
367
+ | `default` / `d` | Default value | `{{ missing\|default:"N/A" }}` |
368
+ | `default_if_none` | Default if null | `{{ val\|default_if_none:"None" }}` |
369
+ | `yesno` | Boolean to text | `{{ true\|yesno:"Yes,No" }}` → `Yes` |
370
+ | `pluralize` | Pluralize suffix | `{{ count\|pluralize }}` → `s` |
371
+
372
+ ### Misc Filters (2)
373
+
374
+ | Filter | Description | Example |
375
+ |--------|-------------|---------|
376
+ | `items` | Dict to pairs | `{% for k,v in dict\|items %}` |
377
+ | `unordered_list` | Nested list to HTML | `{{ items\|unordered_list }}` |
346
378
 
347
379
  ---
348
380
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/filters/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/filters/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1983,9 +1983,18 @@ var sort = (value, reverse2 = false) => {
1983
1983
  return reverse2 ? sorted.reverse() : sorted;
1984
1984
  };
1985
1985
  var unique = (value) => {
1986
- if (Array.isArray(value))
1987
- return [...new Set(value)];
1988
- return value;
1986
+ if (!Array.isArray(value))
1987
+ return value;
1988
+ const seen = new Set;
1989
+ const result = [];
1990
+ for (let i = 0;i < value.length; i++) {
1991
+ const v = value[i];
1992
+ if (!seen.has(v)) {
1993
+ seen.add(v);
1994
+ result.push(v);
1995
+ }
1996
+ }
1997
+ return result;
1989
1998
  };
1990
1999
  var make_list = (value) => {
1991
2000
  if (Array.isArray(value))
@@ -2358,7 +2367,12 @@ var max = (value, attribute, defaultValue) => {
2358
2367
  }
2359
2368
  return maxItem;
2360
2369
  }
2361
- return Math.max(...value);
2370
+ let maxVal = value[0];
2371
+ for (let i = 1;i < value.length; i++) {
2372
+ if (value[i] > maxVal)
2373
+ maxVal = value[i];
2374
+ }
2375
+ return maxVal;
2362
2376
  };
2363
2377
  var min = (value, attribute, defaultValue) => {
2364
2378
  if (!Array.isArray(value) || value.length === 0)
@@ -2372,7 +2386,12 @@ var min = (value, attribute, defaultValue) => {
2372
2386
  }
2373
2387
  return minItem;
2374
2388
  }
2375
- return Math.min(...value);
2389
+ let minVal = value[0];
2390
+ for (let i = 1;i < value.length; i++) {
2391
+ if (value[i] < minVal)
2392
+ minVal = value[i];
2393
+ }
2394
+ return minVal;
2376
2395
  };
2377
2396
  var sum = (value, attribute, start = 0) => {
2378
2397
  if (!Array.isArray(value))
@@ -2662,7 +2681,7 @@ var xmlattr = (value, autospace = true) => {
2662
2681
  if (val === true) {
2663
2682
  attrs.push(key);
2664
2683
  } else if (val !== false && val != null) {
2665
- const escaped = String(val).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2684
+ const escaped = Bun.escapeHTML(String(val));
2666
2685
  attrs.push(`${key}="${escaped}"`);
2667
2686
  }
2668
2687
  }
@@ -3242,9 +3261,12 @@ class Runtime {
3242
3261
  }
3243
3262
  cycleState = new Map;
3244
3263
  renderCycleSync(node, ctx) {
3245
- const key = node.values.map((v) => JSON.stringify(v)).join(",");
3264
+ const key = `cycle_${node.line}_${node.column}`;
3246
3265
  const currentIndex = this.cycleState.get(key) ?? 0;
3247
- const values = node.values.map((v) => this.eval(v, ctx));
3266
+ const values = [];
3267
+ for (let i = 0;i < node.values.length; i++) {
3268
+ values.push(this.eval(node.values[i], ctx));
3269
+ }
3248
3270
  const value = values[currentIndex % values.length];
3249
3271
  this.cycleState.set(key, currentIndex + 1);
3250
3272
  if (node.asVar) {
@@ -3276,12 +3298,16 @@ class Runtime {
3276
3298
  const key = `ifchanged_${node.line}_${node.column}`;
3277
3299
  let currentValue;
3278
3300
  if (node.values.length > 0) {
3279
- currentValue = node.values.map((v) => this.eval(v, ctx));
3301
+ const values = [];
3302
+ for (let i = 0;i < node.values.length; i++) {
3303
+ values.push(this.eval(node.values[i], ctx));
3304
+ }
3305
+ currentValue = values;
3280
3306
  } else {
3281
3307
  currentValue = this.renderNodesSync(node.body, ctx);
3282
3308
  }
3283
3309
  const lastValue = this.ifchangedState.get(key);
3284
- const changed = JSON.stringify(currentValue) !== JSON.stringify(lastValue);
3310
+ const changed = !this.deepEqual(currentValue, lastValue);
3285
3311
  this.ifchangedState.set(key, currentValue);
3286
3312
  if (changed) {
3287
3313
  if (node.values.length > 0) {
@@ -4028,6 +4054,28 @@ class Runtime {
4028
4054
  }
4029
4055
  return true;
4030
4056
  }
4057
+ deepEqual(a, b) {
4058
+ if (a === b)
4059
+ return true;
4060
+ if (a == null || b == null)
4061
+ return a === b;
4062
+ const typeA = typeof a;
4063
+ const typeB = typeof b;
4064
+ if (typeA !== typeB)
4065
+ return false;
4066
+ if (typeA !== "object")
4067
+ return false;
4068
+ if (Array.isArray(a)) {
4069
+ if (!Array.isArray(b) || a.length !== b.length)
4070
+ return false;
4071
+ for (let i = 0;i < a.length; i++) {
4072
+ if (!this.deepEqual(a[i], b[i]))
4073
+ return false;
4074
+ }
4075
+ return true;
4076
+ }
4077
+ return JSON.stringify(a) === JSON.stringify(b);
4078
+ }
4031
4079
  isIn(needle, haystack) {
4032
4080
  if (Array.isArray(haystack))
4033
4081
  return haystack.includes(needle);
@@ -78,6 +78,7 @@ export declare class Runtime {
78
78
  evaluate(node: ExpressionNode, ctx: Context): Promise<any>;
79
79
  private stringify;
80
80
  private isTruthy;
81
+ private deepEqual;
81
82
  private isIn;
82
83
  private toIterable;
83
84
  addFilter(name: string, fn: FilterFunction): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "binja",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "High-performance Jinja2/Django template engine for Bun",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",