Skip to content

fix(go): make the trim filter convert values and strip Unicode whitespace like Rust - #989

Merged
mitsuhiko merged 2 commits into
mitsuhiko:mainfrom
lprnmns:go-trim-like-rust
Oct 29, 2026
Merged

mitsuhiko merged 2 commits into
mitsuhiko:mainfrom
lprnmns:go-trim-like-rust

Conversation

@lprnmns

@lprnmns lprnmns commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

The Go trim filter differed from Rust in two ways:

template Rust Go before
{{ 5|trim|length }} 1 0
{{ true|trim("T") }} rue True
{{ 12345|trim("15") }} 234 12345
{{ " x "|trim }} x  x 
{{ "\vx\f"|trim }} x \vx\f
  1. Values that are not strings were returned unchanged. Rust's trim takes a StringInput, like upper/lower (fix(go): convert non-string values in string filters like Rust #985). It now uses stringInput, so undefined values also fail in strict mode like the other string filters.
  2. Without an argument, Go stripped only " \t\n\r", while Rust uses str::trim, which strips all Unicode whitespace. Go's strings.TrimSpace covers the same set, so it now uses that. With a chars argument, strings.Trim is used as before.

I compared 18 templates with the Python bindings (Rust 3.0.4): none, lists, safe strings, a non-string chars argument, and characters on both sides of the whitespace boundary (U+0085, U+3000, U+2028 are whitespace; U+200B, U+180E are not). All of them match.

Tests: TestTrimLikeRust; five of its cases fail without the change. go test ./... and gofmt pass. Added a changelog entry.

@mitsuhiko
mitsuhiko merged commit 0d0df9d into mitsuhiko:main Oct 29, 2026
19 checks passed
eleboucher pushed a commit to eleboucher/homelab that referenced this pull request Nov 10, 2026
…#2569)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [github:mitsuhiko/minijinja](https://github.com/mitsuhiko/minijinja) | tools | minor | `3.0.2` → `3.1.0` |

---

### Release Notes

<details>
<summary>mitsuhiko/minijinja (github:mitsuhiko/minijinja)</summary>

### [`v3.1.0`](https://github.com/mitsuhiko/minijinja/blob/HEAD/CHANGELOG.md#310)

[Compare Source](mitsuhiko/minijinja@3.0.5...3.1.0)

This release adds output spans and memory limits through fuel, and fixes many
differences to Jinja2 in both Rust and Go.  Fuel now also accounts for memory and
work done in filters and operators, so templates consume more fuel than before and
fuel budgets might need adjusting.  In Go, maps created by templates now keep the
type of their keys and their insertion order; `Value.Raw` returns a `*value.Map`
for them and `Value.AsMap` returns a copy with keys converted to strings.

- Fuel now also limits memory and the work done inside filters and operators, not just the number of instructions.  Templates consume somewhat more fuel than before, so budgets might need adjusting.  [#&#8203;483](mitsuhiko/minijinja#483)
- Added `State::consume_fuel` in Rust and `State.ConsumeFuel` in Go so that custom filters and functions can charge fuel.  [#&#8203;483](mitsuhiko/minijinja#483)
- Added `Template::render_with_spans` in Rust and `Template.RenderWithSpans` in Go to map rendered output back to the template source.  [#&#8203;1004](mitsuhiko/minijinja#1004)
- Added the `count` argument to the `replace` filter for Jinja2 compatibility in Rust.  [#&#8203;1013](mitsuhiko/minijinja#1013)
- The datetime filters in `minijinja-contrib` now fall back to jiff's bundled time zone database for names missing from the system database.  [#&#8203;1008](mitsuhiko/minijinja#1008)
- Fixed booleans sorting separately from numbers.  They now compare, sort and hash like `0` and `1` in Rust and Go.
- Fixed `max` and `groupby` returning the last of multiple equal items instead of the first for Jinja2 compatibility in Rust and Go.
- Fixed `~` and `+` double escaping safe strings or not escaping unsafe ones when combining them with auto escaping enabled in Rust and Go.
- Fixed `first`, `last`, `length`, `count`, `items`, `reverse`, `join` and `groupby` handling `none` and undefined values differently from Jinja2 in Rust and Go.
- Fixed final sigma, titlecase and special case mappings in the `upper`, `lower`, `capitalize` and `title` filters in Rust and Go.
- Fixed `reverse` and `last` not reversing maps and other reversible iterables.  `last` now also works on maps.
- Fixed repeating strings and sequences a negative number of times failing instead of producing an empty result, and repeating safe strings losing their safety.
- Fixed integer math between `2**127` and `2**128`, negating the smallest 128-bit integer and `divisibleby` with a zero divisor in Rust and Go.
- Fixed the `even` and `odd` tests for big integers and floats with an integer value.
- Fixed `super()` panicking at the top level of an included template and `loop(...)` misbehaving in included templates, blocks and macros.
- Fixed slicing with a negative step panicking on empty values and returning wrong items for some bounds.
- Fixed `split(none, n)` returning trailing whitespace as an extra item.
- Errors raised while writing the value of `{{ ... }}` now point to the whole expression.
- Constant folding no longer creates strings or sequences larger than 1KB at compile time.
- Improved the performance of string slicing, string concatenation and the `title` filter.
- Go: maps now keep the type of their keys and their insertion order like in Rust.  The new `value.Map` type gives access to such maps; `Value.AsMap` converts their keys to strings.
- Go: added support for integers outside the 64-bit range to arithmetic, comparisons, `tojson`, the `int`, `float` and `round` filters and the `even`, `odd` and `integer` tests.
- Go: maps can now be compared and sorted, and `==` no longer rounds integers to floats.
- Go: fixed `caller`, `super()`, `loop(x)`, macro auto escaping, blocks of included templates, the template reported for code in blocks and macros and filter chains in `{% filter %}` blocks to behave like in Rust.
- Go: fixed operators and the `string`, `safe`, `sum` and `indent` filters accepting undefined values with strict undefined behavior.
- Go: fixed many filters (`batch`, `slice`, `length`, `first`, `last`, `abs`, `items`, `split`, `attr` and others) silently accepting invalid values or arguments instead of failing like in Rust.
- Go: fixed `in` on strings, `+` on iterables, `chain` results, `groupby` groups, namespaces, unsigned 64-bit integers and float literals such as `1e400` to behave like in Rust.

### [`v3.0.5`](https://github.com/mitsuhiko/minijinja/blob/HEAD/CHANGELOG.md#305)

[Compare Source](mitsuhiko/minijinja@3.0.4...3.0.5)

- Fixed a panic or abort in Rust when buffering an iterator that reports a huge size hint, or when passing a huge count to the `batch` or `slice` filters.  Filters like `list`, `sort`, `reverse`, `map`, `slice` and `batch` as well as slicing and concatenating sequences now cap how much they preallocate, so `[1, 2]|batch(4611686018427387904)` is `[[1, 2]]` instead of failing with "capacity overflow".  [#&#8203;483](mitsuhiko/minijinja#483)
- Fixed floats in Go switching to exponent notation from one million up, so `1234567.5` printed as `1.2345675e+06`.  Like in Rust, a float now prints as its shortest exact decimal without an exponent, so `1234567.5` is `1234567.5` and `1e20` is `100000000000000000000.0`.  Inside lists and maps, exponent notation is only used below `1e-4` and from `1e16` up, written like `1e20` and `1e-5`.  NaN now prints as `NaN`, and infinity inside a list as `inf` instead of `+Inf`.  [#&#8203;984](mitsuhiko/minijinja#984)
- Fixed `%s` in the `format` filter formatting floats with `%g` rules, so `"%s"|format(1234567.5)` was `1.23457e+06`.  Like in Python, floats are now formatted like `str()` does: `1234567.5`, `1e+16`, `1e-05` or `nan`.  The `0`, `+` and space flags are ignored for floats and strings with `%s`, like in Python.  This applies to both Rust and Go.  [#&#8203;984](mitsuhiko/minijinja#984)
- Fixed the `tojson` filter in Go writing floats like integers.  Like in Rust, a float stays a float in the output, so `1.0|tojson` is `1.0` instead of `1`, large and small magnitudes use exponent notation (`1.5e+16`, `2.5e-7`) and infinity becomes `null` instead of an error.  The same applies to values rendered with JSON auto-escaping.  [#&#8203;983](mitsuhiko/minijinja#983)
- Fixed the `upper`, `lower`, `capitalize`, `title` and `replace` filters in Go ignoring values that are not strings.  Like in Rust, the value and the `replace` arguments are converted to strings first, so `1.5|replace(".", ",")` is `1,5` and `true|upper` is `TRUE`, and a number passed to `replace` is no longer treated as an empty string.  [#&#8203;985](mitsuhiko/minijinja#985)
- Fixed slicing and the `in` operator on iterables such as `range()` in Go.  Like in Rust, `range(5)[:2]` is now `[0, 1]` instead of failing with "cannot slice iterator", and `3 in range(5)` is `true` instead of `false`.  Slicing `none` or undefined gives an empty list like in Rust.  Iterables now also print, compare, serialize with `tojson` and `pprint` like lists, so `range(2) == [0, 1]` is `true` and `[range(2)]` prints as `[[0, 1]]` instead of `[<iterator>]`.  The `in` operator now also works on custom sequence, iterable and map objects.  [#&#8203;986](mitsuhiko/minijinja#986)
- Fixed `none` in Go not being treated as an empty sequence by the `sort`, `unique`, `select`, `reject`, `map`, `groupby`, `join` and `urlencode` filters and the `iterable` test.  Like in Rust, `none|sort` is now `[]` and `none|join` is an empty string instead of `None`.  [#&#8203;987](mitsuhiko/minijinja#987)
- Fixed the `odd`, `even` and `divisibleby` tests in Go ignoring booleans, and `divisibleby` ignoring a float divisor.  Like in Rust, booleans count as `0` and `1`, so `true is odd` is true, and `6.5 is divisibleby(0.5)` is true.  [#&#8203;988](mitsuhiko/minijinja#988)
- Fixed `str.format` in `pycompat` cutting floats to six significant digits when no precision is given.  Like in Python, such floats are now formatted like `str()` does, so `'{}'.format(3.14159265)` is `3.14159265`, `'{}'.format(1234567.0)` is `1234567.0` instead of `1.23457e+06` and `'{}'.format(0.0)` is `0.0` instead of `0`.  [#&#8203;991](mitsuhiko/minijinja#991)
- Fixed the `trim` filter in Go ignoring values that are not strings and only stripping ASCII spaces, tabs and newlines by default.  Like in Rust, `5|trim|length` is now `1`, and Unicode whitespace such as a non-breaking space is stripped.  [#&#8203;989](mitsuhiko/minijinja#989)
- Fixed undefined values not being treated as empty sequences by the `sort`, `unique`, `select`, `reject`, `selectattr`, `rejectattr`, `map`, `batch` and `groupby` filters in Go, and `none` by `batch`, `selectattr` and `rejectattr`.  Like in Rust, `undefined|sort` is now `[]` with lenient undefined behavior, while strict and semi-strict undefined behavior still fail except for `join` and `groupby`.  [#&#8203;990](mitsuhiko/minijinja#990)
- Fixed a panic in `compile_expression` when the expression contains `}}` followed by more input, such as `}} x`.  This is now a syntax error, like the same text inside a template.  [#&#8203;992](mitsuhiko/minijinja#992)

### [`v3.0.4`](https://github.com/mitsuhiko/minijinja/blob/HEAD/CHANGELOG.md#304)

[Compare Source](mitsuhiko/minijinja@3.0.3...3.0.4)

- Fixed `str.count` in `pycompat` looping forever when counting an empty string.  Like in Python, `'abc'.count('')` is now `4`.
- Fixed `str.islower` and `str.isupper` in `pycompat` returning false for strings with spaces, digits or other uncased characters, and the `str.is*` predicates returning true for an empty string.  They now follow Python, so `'foo bar'.islower()` is true and `''.isdigit()` is false.
- Fixed `str.find` and `str.rfind` in `pycompat` returning byte offsets.  Like in Python they now return character offsets, so `'über'.find('e')` is `2`.
- Fixed integer addition, subtraction and multiplication in Go losing precision above 2\*\*53 and clamping results that overflow 64 bits, because they were computed with floats.  They are now exact, and like in Rust a result that doesn't fit 64 bits becomes a big integer, so `9007199254740993 + 0` is `9007199254740993` and `9223372036854775807 + 1` is `9223372036854775808`.  [#&#8203;981](mitsuhiko/minijinja#981)
- Fixed booleans not being usable as integers in `-`, `*`, `/`, `//` and `%` and for repeating strings and sequences in Go.  Like in Rust and Jinja2, `true - 1` is `0` and `"ab" * true` is `ab`.
- Fixed `**` failing with a negative integer exponent in Rust.  Like in Jinja2, `2 ** -1` is now `0.5`.  Zero to a negative power now always fails in Rust and Go like a division by zero, instead of producing `inf` for floats in Rust and for all numbers in Go.  [#&#8203;982](mitsuhiko/minijinja#982)
- Fixed `**` on integers in Go being computed with floats.  Like in Rust the result is now exact up to 128 bits and fails beyond that, a float base stays a float so `2.0 ** 3` is `8.0`, and booleans count as integers.
- Fixed the `sort` filter ignoring a comma-separated list of attributes in Go.  Like in Rust, `sort(attribute="name, state")` now sorts by `name` and then by `state` instead of leaving the items in their original order.  [#&#8203;979](mitsuhiko/minijinja#979)
- Fixed the `sort` filter comparing strings case-sensitively when sorting by several attributes in Rust and Go.  Like in Jinja2, each part of the key is now compared case-insensitively unless `case_sensitive` is set.  An attribute list with whitespace-only entries such as `"name, "` also no longer sorts by an empty attribute in Rust.
- Added the `attribute` and `start` arguments to the `sum` filter and the `attribute` argument to the `join` filter for Jinja2 compatibility in Rust and Go.  Like in Jinja2 the arguments can be passed positionally or by keyword, and the separator of `join` can also be passed as `d`.  In Go the first positional argument of `sum` is now the attribute rather than the start value, so `sum(100)` needs to be written as `sum(start=100)`.  Go previously ignored unknown keyword arguments to `sum` and `join` and now fails like Rust.  Like in Jinja2, `sum` in Rust can now also concatenate lists when given a list as `start`.  [#&#8203;980](mitsuhiko/minijinja#980)
- Fixed the handling of none arguments to the `int`, `float` and `round` filters in Go.  Like in Rust they now count as not given, so `2.5|round(none)` is `2.0` instead of an error.
- Fixed the `join` filter dropping a separator that is not a string in Go.  Like in Rust it is converted to a string, so `[1, 2]|join(3)` is `132`.

### [`v3.0.3`](https://github.com/mitsuhiko/minijinja/blob/HEAD/CHANGELOG.md#303)

[Compare Source](mitsuhiko/minijinja@3.0.2...3.0.3)

- Re-release of 3.0.2 without code changes.  The Python package for 3.0.2 could not be published to PyPI because the 32-bit Linux wheel failed to build on the new Ubuntu 26.04 GitHub Actions runners, so 3.0.3 is the first release with the 3.0.2 changes on PyPI.  All other packages are identical to 3.0.2.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xOTkuMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE5OS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/2569
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants