@rhinostone/swig 2.8.0 → 2.8.1

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/HISTORY.md CHANGED
@@ -1,3 +1,18 @@
1
+ [2.8.1](https://github.com/gina-io/swig/tree/v2.8.1) / 2026-10-20
2
+ -----------------------------------------------------------------
3
+
4
+ * **Added** A "What's new in v<version>" section at the top of the README, regenerated from the release notes at every cut
5
+
6
+ * **Fixed** Refreshed stale README claims — the benchmark summary now reflects the latest measured run (swig leads on all five workloads; the previous table predated the 2.2.0 escape-filter rewrite and showed nunjucks ahead on simple var output), and the security bullet no longer pins an exact CVE regression-test count nor conflates the prototype-chain hardening with CVE-2023-25345 (a directory-traversal fix)
7
+
8
+ * **Fixed** README completeness pass against the 2.x release line — the feature list now covers the async-loader render path (callback dispatch with loader.async, dynamic extends included) and the single-runtime-dependency posture, the "How it works" section explains the runtime-only strict-CSP path, and the Jinja2/Django migration notes no longer list the default filter as absent (it has been built into native swig since upstream 2014)
9
+
10
+ * **Fixed** The v0.9.0 changelog entry's PHP date-format citation now links to the canonical `https://www.php.net/manual/en/function.date.php` instead of the plain-HTTP `http://php.net/date` it had carried since upstream. The old form still resolves — it 301s through to exactly that URL — so this is the same destination over HTTPS, with the link text unchanged; it removes the last plain-HTTP link a link-health scan can flag in this repo (reported twice, gina-io/gina#51 and #58). Documentation only; no runtime or API change.
11
+
12
+ * **Fixed** The bundled DateZ attribution banner now points at `https://github.com/tn0ms/DateZ`, following the fourth rename of that upstream account. The previous `tomoio` form still resolves — GitHub 301s a renamed account through to its current owner — so this is the same destination, with the misspelled upstream `LISENCE` filename preserved because that is genuinely how the file is named there. The banner ships in every `dist/` artifact, so the corrected URL reaches consumers at the next publish. Documentation only; no runtime or API change.
13
+
14
+ * **Changed** Upgraded the ESLint dev dependency from 9.x, which its maintainers no longer support, to 10.x. The flat-config eslint.config.js carries over unchanged, and make lint reports the same results as under 9.x. ESLint 10 raises the lint toolchain Node floor to ^20.19.0, ^22.13.0 or >=24, which affects development and CI only; the published package is unaffected and its only runtime dependency remains @rhinostone/swig-core.
15
+
1
16
  [2.8.0](https://github.com/gina-io/swig/tree/v2.8.0) / 2026-08-02
2
17
  -----------------------------------------------------------------
3
18
 
@@ -565,7 +580,7 @@ Migrating from v0.x.x? The upstream wiki has since been deleted; see the individ
565
580
  * **Added** New `raw` tag.
566
581
  * **Changed** Swig is no longer node 0.4 compatible.
567
582
  * **Fixed** Filter `date('f')` for 10am times.
568
- * **Fixed** Filter `date('r')` returns in UTC date format. This is more correct tospec RFC2822, per [php.net/date](http://php.net/date).
583
+ * **Fixed** Filter `date('r')` returns in UTC date format. This is more correct tospec RFC2822, per [php.net/date](https://www.php.net/manual/en/function.date.php).
569
584
  * **Fixed** Filter `add` when adding numbers/numbers+strings together.
570
585
  * **Fixed** Tests for error messages that changed in node >0.6.0.
571
586
 
package/README.md CHANGED
@@ -32,15 +32,28 @@ Features
32
32
  --------
33
33
 
34
34
  * Available for node.js **and** major web browsers.
35
+ * **Strict-CSP browser runtime** — AOT-compile templates ahead of time (`swig compile --recursive --register`) and render them with the runtime-only bundle (`dist/swig.runtime.min.js`, ~22 KB) — no parser, no `new Function`, no `unsafe-eval` required.
35
36
  * [Express](https://expressjs.com/) compatible.
37
+ * **Async template loading** — back the loader with S3 / Redis / HTTP / any callback API: set `loader.async = true` and pass a callback to `renderFile` / `compileFile`; `extends` / `include` / `import` resolve at render time, dynamic `{% extends %}` paths included.
36
38
  * Object-Oriented template inheritance.
37
39
  * Apply filters and transformations to output in your templates.
38
- * **Hardened against prototype-pollution** — `__proto__` / `constructor` / `prototype` blocked at parser, tag-side, and IR-emission layers. CVE-2023-25345 fully patched. 11 CVE regression cases under [`tests/regressions.test.js`](./tests/regressions.test.js).
40
+ * **Security-hardened** — prototype-pollution vectors (`__proto__` / `constructor` / `prototype`) blocked at parser, tag-side, and IR-emission layers; template-driven file reads outside the loader root rejected (CVE-2023-25345 directory traversal, patched in 2.7.1). Dedicated CVE regression suite in [`tests/regressions.test.js`](./tests/regressions.test.js).
39
41
  * Automatically escapes all variable output (HTML by default; configurable per-call).
40
42
  * Lots of iteration and conditionals supported.
41
- * Robust without the bloat.
43
+ * Robust without the bloat — a single runtime dependency ([`@rhinostone/swig-core`](https://www.npmjs.com/package/@rhinostone/swig-core)).
42
44
  * Extendable and customizable — register custom filters, tags, and loaders per-instance.
43
45
 
46
+ What's new in v2.8.1
47
+ --------------------
48
+
49
+ * **Fixed — README corrections now on npm.** The 2.8.0 README listed CVE-2023-25345 under the prototype-chain hardening; it is the directory-traversal fix, and the security bullet now says so without pinning an exact CVE regression-test count. The benchmark summary reflects the latest measured run (swig leads on all five workloads; the previous table predated the 2.2.0 escape-filter rewrite and showed nunjucks ahead on simple var output). The Jinja2/Django migration notes no longer list the `default` filter as absent — it has been built into native swig since upstream 2014.
50
+ * **Fixed — README completeness for the 2.x line.** The feature list now covers the async-loader render path (callback dispatch with `loader.async`, dynamic `extends` included) and the single-runtime-dependency posture, and "How it works" explains the runtime-only strict-CSP path.
51
+ * **Added — a "What's new" section.** The README now opens with a section like this one, regenerated from the release notes at every cut.
52
+ * **Fixed — attribution and changelog links.** The bundled DateZ attribution banner points at `https://github.com/tn0ms/DateZ` after the upstream account's rename, and the v0.9.0 changelog's PHP date-format citation links to the canonical HTTPS `php.net` page. Both old links still resolved; documentation only, no runtime or API change.
53
+ * **Changed — ESLint 10 for development.** ESLint 9 is no longer supported by its maintainers, so the lint toolchain moves to ESLint 10 with the flat config unchanged. Running `make lint` now needs Node ^20.19.0, ^22.13.0 or >=24; the published package and its runtime Node floor are unaffected.
54
+
55
+ See the full [HISTORY.md](./HISTORY.md) and [ROADMAP.md](./ROADMAP.md).
56
+
44
57
  Benchmarks
45
58
  ----------
46
59
 
@@ -50,7 +63,7 @@ Benchmarks
50
63
  cd benchmarks && npm install && node render.js
51
64
  ```
52
65
 
53
- In production-typical settings (autoescape on), `@rhinostone/swig` outperforms Nunjucks on iteration-heavy templates by 2–3.5× and ties on simple control flow. See [`benchmarks/README.md`](./benchmarks/README.md) for the methodology, the full result table, and how to reproduce on your own hardware.
66
+ In production-typical settings (autoescape on), `@rhinostone/swig` leads Nunjucks on all five workload shapes — from ~1.8× on simple variable output to 3.5–5.5× on iteration-heavy templates (median of 3 runs, 2026-08). See [`benchmarks/README.md`](./benchmarks/README.md) for the methodology, the full result table, and how to reproduce on your own hardware.
54
67
 
55
68
  Need Help? Have Questions? Comments?
56
69
  ------------------------------------
@@ -137,7 +150,7 @@ Swig is *inspired by* Jinja2 and Django, not a drop-in replacement. Common pitfa
137
150
  * **`{% with x=1 %}` → `{% set x = 1 %}`**, and no block-form `{% set %}…{% endset %}`.
138
151
  * **No `{% from "f" import x %}` — use `{% import "f" as ns %}` + `ns.x` instead**.
139
152
  * **Method calls require parens** — Django auto-invokes `x.get_absolute_url`; Swig needs `x.get_absolute_url()`.
140
- * **~25 Jinja2 filters are absent** — `default`, `truncate`, `tojson`, `round`, `int`, `float`, `map`, `select`, `batch`, `trim`, etc. Register them via `swig.setFilter(name, fn)`.
153
+ * **Many Jinja2 filters are absent** — `truncate`, `tojson`, `round`, `int`, `float`, `map`, `select`, `batch`, `trim`, etc. (`default` **is** built in). Register missing ones via `swig.setFilter(name, fn)` — or use [@rhinostone/swig-jinja2](https://www.npmjs.com/package/@rhinostone/swig-jinja2), which ships 39 of them natively.
141
154
 
142
155
  Full parity tables and workaround patterns: **[Migration Guide](https://gina.io/docs/templating/swig/migration)**.
143
156
 
@@ -148,6 +161,8 @@ Swig reads template files and translates them into cached JavaScript functions.
148
161
 
149
162
  In `2.x`, frontend parsers (native Swig syntax in [@rhinostone/swig](https://www.npmjs.com/package/@rhinostone/swig), Twig syntax in [@rhinostone/swig-twig](https://www.npmjs.com/package/@rhinostone/swig-twig), Python Jinja2 syntax in [@rhinostone/swig-jinja2](https://www.npmjs.com/package/@rhinostone/swig-jinja2), Django Template Language syntax in [@rhinostone/swig-django](https://www.npmjs.com/package/@rhinostone/swig-django)) emit a shared intermediate representation. The backend in [@rhinostone/swig-core](https://www.npmjs.com/package/@rhinostone/swig-core) lowers IR to JS. New flavors plug in at the frontend without touching the runtime.
150
163
 
164
+ For strict-CSP targets the compile pipeline can be skipped entirely: AOT-compile templates with the CLI (`swig compile --recursive --register`) and execute the resulting bundle with the runtime-only build (`dist/swig.runtime.min.js`), which contains no parser and no `new Function`.
165
+
151
166
  License
152
167
  -------
153
168
 
package/ROADMAP.md CHANGED
@@ -16,7 +16,7 @@ _No near-term scheduled items. See [Future (post-2.0)](#future-post-20) for upco
16
16
  | --- | --- |
17
17
  | Planned | Async parse path for the remaining dynamic targets — runtime-resolved `{% import %}` / `{% from %}` paths on the async-codegen branch. Static-target async dispatch shipped in 2.2.0; dynamic `{% extends %}` shipped in 2.5.2 (native + Twig + Jinja2) and dynamic `{% include %}` paths already resolve (the include path has always been an expression). Dynamic `import` / `from` are on hold pending consumer demand. |
18
18
  | Planned | Modern browser-test harness. The legacy phantomjs runner was removed; a replacement (e.g. Playwright or JSDOM) has not yet landed, so browser parity is verified in the interim via the production build plus a symbol grep. (The `mocha` → `node:test` runner migration, the `expect.js` → in-repo assertion-shim swap, and the `blanket` → `node:test` built-in coverage migration have all shipped.) |
19
- | On demand | Runtime-only browser bundles for the Twig, Jinja2, and Django frontends. The shared runtime factory already supports them — each needs its own bundle entry and build target, since filter catalogs are per-flavor. The native `dist/swig.runtime.min.js` shipped in 2.8.0; the flavor bundles land when a consumer needs one. |
19
+ | On demand | Ahead-of-time browser support for the Twig, Jinja2, and Django frontends, in two parts that ship together. Runtime-only bundles: the shared runtime factory already supports them, and each flavor needs its own bundle entry and build target, since filter catalogs are per-flavor. A flavor-aware compile step: `swig compile --register` compiles with the native parser only, so flavor templates are precompiled programmatically until it lands. The native `dist/swig.runtime.min.js` shipped in 2.8.0; the flavor pieces land when a consumer needs them. |
20
20
 
21
21
  ---
22
22
 
@@ -25,7 +25,7 @@ _No near-term scheduled items. See [Future (post-2.0)](#future-post-20) for upco
25
25
  ### v2.8.0 (August 2026)
26
26
 
27
27
  - Added ahead-of-time template registration: `swig.register(path, fn)` and `swig.registerBundle(map)` place pre-compiled template functions into the template cache under loader-normalized keys, so `include`, `compileFile`, and `renderFile` resolve them without a compiler. Available on all four frontends (native, Twig, Jinja2, Django). `swig compile --recursive --register` emits a bundle that registers itself on load and also exports the template map, so a page needs no per-template wiring.
28
- - Added a runtime-only browser build — `dist/swig.runtime.js` and `dist/swig.runtime.min.js` (21 KB minified, roughly a quarter of the full bundle). It executes pre-compiled bundles with the full filter catalog but ships no lexer, parser, or code generator, and therefore contains no `new Function`: pages served under a strict Content-Security-Policy without `unsafe-eval` can render AOT-compiled templates. Every compiling entry point throws a clear error naming the CLI workflow instead of failing obscurely. Also available to Node as `require('@rhinostone/swig/runtime')`.
28
+ - Added a runtime-only browser build — `dist/swig.runtime.js` and `dist/swig.runtime.min.js` (22 KB minified, roughly a quarter of the full bundle). It executes pre-compiled bundles with the full filter catalog but ships no lexer, parser, or code generator, and therefore contains no `new Function`: pages served under a strict Content-Security-Policy without `unsafe-eval` can render AOT-compiled templates. Every compiling entry point throws a clear error naming the CLI workflow instead of failing obscurely. Also available to Node as `require('@rhinostone/swig/runtime')`.
29
29
  - Fixed several template-cache paths that failed silently. A registered template no longer shadows a loadable `{% extends %}` parent — the parent's source is still read through the loader, where previously registering a layout could make a child that rendered correctly start rendering an empty string with no error. The memory loader rejects a climbing path when a `basepath` is set rather than resolving it to a different template than the one requested. Passing a filepath to `run` now caches an entry a later `include` can actually use. The memory cache no longer treats inherited object members as cache hits. `register` reports a disabled cache for every falsy `cache` value, and `registerBundle` validates a whole bundle before committing any of it, so a malformed map cannot leave the registry half-populated.
30
30
  - Fixed browser integration for the new bundles: a self-registering bundle finds the engine whether it is a bare global or a property of the global object (under AMD there is no bare binding, so every template previously went unregistered in silence) and warns when no engine is present; loading a runtime bundle twice, or after the full build, no longer discards existing registrations or replaces a compiler-capable instance; and the runtime entry no longer assumes `window`, so it loads in a worker. Both minified bundles now reference the source map filename that is actually written.
31
31
  - All five packages (`@rhinostone/swig`, `@rhinostone/swig-core`, `@rhinostone/swig-twig`, `@rhinostone/swig-jinja2`, `@rhinostone/swig-django`) released in lockstep at `2.8.0`. Lockstep is now required rather than conventional: the frontends reference modules inside `@rhinostone/swig-core` that exist only from this version forward.
package/context7.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "url": "https://context7.com/gina-io/swig",
3
+ "public_key": "pk_MGD4ulFUKUHnxmzFGuWc8",
4
+ "projectTitle": "Rhinostone Swig",
5
+ "description": "Rhinostone Swig is a simple, powerful, and extendable template engine for Node.js and browsers, supporting native Swig, Twig, Python Jinja2, and Django Template Language syntaxes.",
6
+ "branch": "develop",
7
+ "excludeFolders": [
8
+ ".changes"
9
+ ],
10
+ "excludeFiles": [
11
+ "HISTORY.md",
12
+ "ROADMAP.md",
13
+ "AUTHORS",
14
+ "ISSUE_TEMPLATE.md",
15
+ "PULL_REQUEST_TEMPLATE.md"
16
+ ]
17
+ }
package/dist/swig.js CHANGED
@@ -1,9 +1,13 @@
1
- /*! Swig v2.8.0 | https://github.com/gina-io/swig | @license https://github.com/gina-io/swig/blob/master/LICENSE */
2
- /*! DateZ (c) 2011 Tomo Universalis | @license https://github.com/tomoio/DateZ/blob/master/LISENCE */
1
+ /*! Swig v2.8.1 | https://github.com/gina-io/swig | @license https://github.com/gina-io/swig/blob/master/LICENSE */
2
+ /*! DateZ (c) 2011 Tomo Universalis | @license https://github.com/tn0ms/DateZ/blob/master/LISENCE */
3
3
  (() => {
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __commonJS = (cb, mod) => function __require() {
6
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
6
+ try {
7
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
8
+ } catch (e) {
9
+ throw mod = 0, e;
10
+ }
7
11
  };
8
12
 
9
13
  // packages/swig-core/lib/security.js
@@ -4810,7 +4814,7 @@
4810
4814
  var loaders = require_loaders2();
4811
4815
  var preWalker = require_pre_walker();
4812
4816
  var engine = require_engine();
4813
- exports.version = "2.8.0";
4817
+ exports.version = "2.8.1";
4814
4818
  var defaultOptions = {
4815
4819
  autoescape: true,
4816
4820
  varControls: ["{{", "}}"],