@rhinostone/swig 2.4.3 → 2.5.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 +23 -1
- package/README.md +13 -6
- package/ROADMAP.md +14 -2
- package/dist/swig.js +93 -9
- package/dist/swig.min.js +2 -2
- package/dist/swig.min.js.map +1 -1
- package/eslint.config.js +32 -0
- package/lib/dateformatter.js +1 -1
- package/lib/swig.js +177 -1
- package/lib/tags/extends.js +8 -8
- package/lib/tags/filter.js +1 -1
- package/lib/tags/if.js +5 -6
- package/lib/tags/import.js +6 -6
- package/lib/tags/parent.js +4 -4
- package/lib/tags/set.js +5 -5
- package/package.json +8 -20
- package/.eslintrc.json +0 -24
package/HISTORY.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
[2.5.1](https://github.com/gina-io/swig/tree/v2.5.1) / 2026-05-28
|
|
2
|
+
-----------------------------------------------------------------
|
|
3
|
+
|
|
4
|
+
* **Fixed** Restored the JSDoc blocks on the top-level Swig public API methods (setFilter, setTag, setExtension, precompile, compile, compileFile, render, renderFile, run, invalidateCache) that were inadvertently stripped from lib/swig.js when the Swig constructor body was carved into @rhinostone/swig-core/lib/engine.js. The documentation comments now sit above the corresponding exports.* re-exports where make build-docs and IDE hover tooling read them. No runtime behavior change — the published lib/ code is byte-identical and only the JSDoc surface is updated.
|
|
5
|
+
|
|
6
|
+
* **Changed** Rephrased two stale internal-process tracker references in lib/tags/set.js source comments that survived the prior single-line audit sweep because the markers spanned a line wrap. The explanatory content is preserved verbatim; only the dead tracker tokens are dropped, per the in-repo no-internal-markers-in-shipping-source convention. No behavior change.
|
|
7
|
+
|
|
8
|
+
* **Changed** Migrated the test toolchain from mocha 1.12.0 to the Node.js built-in test runner (node:test) with built-in line coverage, removing the mocha, blanket, and travis-cov dev dependencies. This clears all 6 npm audit advisories (4 high, 2 critical) that were rooted in mocha's transitive dependency tree; the full suite passes unchanged and the 95% coverage gate over lib/ is preserved. The published package is unaffected — its only runtime dependency remains @rhinostone/swig-core.
|
|
9
|
+
|
|
10
|
+
* **Changed** Removed the unmaintained phantomjs and mocha-phantomjs browser-test toolchain, dropping the vulnerable form-data (CVE-2025-7783) and the rest of the legacy request dependency subtree from the dev dependency tree. Browser parity is verified through the production bundle build, pending a modern browser-test harness.
|
|
11
|
+
|
|
12
|
+
* **Changed** Upgraded the ESLint dev dependency from 8.57.1 to 9.x and migrated the lint configuration from the deprecated .eslintrc.json (eslintrc format) to the flat-config eslint.config.js, adding the globals dev dependency. The lenient rule set is preserved exactly (no indent enforcement, eqeqeq/no-eval/no-new-func off, semi always, max-len 600, plus an explicit linterOptions.reportUnusedDisableDirectives off to match the eslintrc default). ESLint 9 raises the lint toolchain Node floor to >=18.18, which affects development and CI only; the published package is unaffected and its only runtime dependency remains @rhinostone/swig-core.
|
|
13
|
+
|
|
14
|
+
* **Changed** Upgraded the example/development express dependency from the abandoned 3.x line to 4.x, dropping the vulnerable transitive morgan (CVE-2019-5413) and the legacy connect subtree from the dev dependency tree. The Express view-engine example runs unchanged. The published package is unaffected; its only runtime dependency remains @rhinostone/swig-core.
|
|
15
|
+
|
|
16
|
+
* **Changed** Upgraded the development lodash dependency from 1.3.x to 4.x, dropping the prototype-pollution and command-injection advisories (affecting lodash through 4.17.23) from the dev dependency tree. lodash is a test-only utility and the full suite passes unchanged on 4.x. The published package is unaffected; its only runtime dependency remains @rhinostone/swig-core.
|
|
17
|
+
|
|
18
|
+
[2.5.0](https://github.com/gina-io/swig/tree/v2.5.0) / 2026-05-27
|
|
19
|
+
-----------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
* **Added** @rhinostone/swig-jinja2 — a Python Jinja2-syntax frontend on the shared swig-core engine (13 tags, 39 filters, 16 is-tests, async loader support, autoescape and CVE-2023-25345 guards inherited from swig-core). Releases in lockstep with @rhinostone/swig, @rhinostone/swig-core, and @rhinostone/swig-twig.
|
|
22
|
+
|
|
1
23
|
[2.4.3](https://github.com/gina-io/swig/tree/v2.4.3) / 2026-05-22
|
|
2
24
|
-----------------------------------------------------------------
|
|
3
25
|
|
|
@@ -57,7 +79,7 @@
|
|
|
57
79
|
[2.0.0](https://github.com/gina-io/swig/tree/v2.0.0) / 2026-05-06
|
|
58
80
|
-----------------------------------------------------------------
|
|
59
81
|
|
|
60
|
-
* **Fixed** Refreshed stale external URL references across documentation surfaces from the 2026-04-13 link-health audit (gina-io/gina#18). `README.md`, `packages/swig-core/README.md`, `packages/swig-twig/README.md` — swapped `www.npmjs.org` for the canonical `www.npmjs.com` in the NPM badges (the old `.org` form now redirects). `README.md` — rewrote the "Swig v0.x → v1.x migration notes" bullet, since the `paularmstrong/swig/wiki/Migrating-from-...` page was deleted upstream (302s to repo root). `HISTORY.md` — dropped the three dead upstream-wiki links around the v1.0.0 / v1.0.0-pre1 entries; the breaking-change prose stays intact. `browser/comments.js` — updated the DateZ `@license` URL from `TomoUniversalis/DateZ` to `ocrybit/DateZ` (the upstream GitHub user was renamed). `packages/swig-core/lib/dateformatter.js` — dropped the dead `
|
|
82
|
+
* **Fixed** Refreshed stale external URL references across documentation surfaces from the 2026-04-13 link-health audit (gina-io/gina#18). `README.md`, `packages/swig-core/README.md`, `packages/swig-twig/README.md` — swapped `www.npmjs.org` for the canonical `www.npmjs.com` in the NPM badges (the old `.org` form now redirects). `README.md` — rewrote the "Swig v0.x → v1.x migration notes" bullet, since the `paularmstrong/swig/wiki/Migrating-from-...` page was deleted upstream (302s to repo root). `HISTORY.md` — dropped the three dead upstream-wiki links around the v1.0.0 / v1.0.0-pre1 entries; the breaking-change prose stays intact. `browser/comments.js` — updated the DateZ `@license` URL from `TomoUniversalis/DateZ` to `ocrybit/DateZ` (the upstream GitHub user was renamed). `packages/swig-core/lib/dateformatter.js` — dropped the dead `tomouniversalis.com` parenthetical from the DateZ copyright comment (domain NXDOMAINs). `.changes/v1.0.0.md` and `.changes/v1.0.0-pre1.md` synced to match the rewritten `HISTORY.md` lines so future `changie merge` runs stay idempotent. Documentation and comment-only; no runtime or API change.
|
|
61
83
|
|
|
62
84
|
* **Changed** `2.0.0` stable. Multi-flavor architecture (introduced across `2.0.0-alpha.1` through `2.0.0-alpha.5`) is the production-ready cut. No functional or API changes since `2.0.0-alpha.5`; the `alpha.6`–`alpha.8` cycle was metadata republishes plus removal of the soft-deprecated `exports.parse` Path B wrapper from `@rhinostone/swig-twig`. IR ABI is stable from this release onward; cross-package dependencies pin exact versions and frontends + core release in lockstep. README messaging refreshed across all three packages to reflect production-ready status; package descriptions cleaned of historical internal-tracking references.
|
|
63
85
|
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ Swig
|
|
|
3
3
|
|
|
4
4
|
[](https://github.com/gina-io/swig/actions/workflows/ci.yml) [](https://www.npmjs.com/package/@rhinostone/swig) [](https://www.npmjs.com/package/@rhinostone/swig) [](https://socket.dev/npm/package/@rhinostone/swig)
|
|
5
5
|
|
|
6
|
-
> **Multi-flavor template engine** for Node.js and browsers — native Swig syntax (Jinja2/Django-inspired) and
|
|
6
|
+
> **Multi-flavor template engine** for Node.js and browsers — native Swig syntax (Jinja2/Django-inspired), Twig syntax, and Python Jinja2 syntax via dedicated frontends sharing one IR backend. [gina-io/swig](https://github.com/gina-io/swig) started as a maintained continuation of the abandoned [paularmstrong/swig](https://github.com/paularmstrong/swig) (last released 2014) and is now a standalone project. Security and bug fixes ship here.
|
|
7
7
|
|
|
8
8
|
> **Part of the [Gina](https://github.com/gina-io/gina) ecosystem.** This is the built-in template engine for [Gina](https://gina.io) ([npm](https://www.npmjs.com/package/gina)), a Node.js MVC framework with HTTP/2, multi-bundle architecture, and scope-based data isolation.
|
|
9
9
|
|
|
@@ -11,6 +11,8 @@ Swig is a **Jinja2/Django-inspired** template engine for node.js and browsers. T
|
|
|
11
11
|
|
|
12
12
|
> **Coming from Twig?** Install [@rhinostone/swig-twig](https://www.npmjs.com/package/@rhinostone/swig-twig) instead — a dedicated Twig-syntax frontend with closer parity than working around incompatibilities here.
|
|
13
13
|
|
|
14
|
+
> **Coming from Python Jinja2?** Install [@rhinostone/swig-jinja2](https://www.npmjs.com/package/@rhinostone/swig-jinja2) — a dedicated Jinja2-syntax frontend (near-subset) with closer parity than porting to native Swig syntax here.
|
|
15
|
+
|
|
14
16
|
Workspace packages
|
|
15
17
|
------------------
|
|
16
18
|
|
|
@@ -18,9 +20,10 @@ Workspace packages
|
|
|
18
20
|
| --- | --- | --- |
|
|
19
21
|
| [`@rhinostone/swig`](https://www.npmjs.com/package/@rhinostone/swig) | Native Swig syntax (Jinja2/Django-inspired). Drop-in for `@rhinostone/swig@1.x` consumers. | Upgrading from `@rhinostone/swig@1.x`, or starting fresh with Swig syntax. |
|
|
20
22
|
| [`@rhinostone/swig-twig`](https://www.npmjs.com/package/@rhinostone/swig-twig) | Twig-syntax frontend with closer Twig parity. | Migrating from PHP Twig, or writing new templates in Twig syntax. |
|
|
23
|
+
| [`@rhinostone/swig-jinja2`](https://www.npmjs.com/package/@rhinostone/swig-jinja2) | Python Jinja2-syntax frontend (near-subset). | Migrating from Python Jinja2, or writing new templates in Jinja2 syntax. |
|
|
21
24
|
| [`@rhinostone/swig-core`](https://www.npmjs.com/package/@rhinostone/swig-core) | Shared IR, backend, and runtime primitives. | Building a custom flavor frontend. Otherwise pulled in transitively. |
|
|
22
25
|
|
|
23
|
-
Each frontend pins the matching `@rhinostone/swig-core` version exactly
|
|
26
|
+
Each frontend pins the matching `@rhinostone/swig-core` version exactly (no caret, no tilde) — frontends and the core release in lockstep on every cut.
|
|
24
27
|
|
|
25
28
|
Features
|
|
26
29
|
--------
|
|
@@ -29,7 +32,7 @@ Features
|
|
|
29
32
|
* [Express](http://expressjs.com/) compatible.
|
|
30
33
|
* Object-Oriented template inheritance.
|
|
31
34
|
* Apply filters and transformations to output in your templates.
|
|
32
|
-
* **Hardened against prototype-pollution** — `__proto__` / `constructor` / `prototype` blocked at parser, tag-side, and IR-emission layers. CVE-2023-25345 fully patched.
|
|
35
|
+
* **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).
|
|
33
36
|
* Automatically escapes all variable output (HTML by default; configurable per-call).
|
|
34
37
|
* Lots of iteration and conditionals supported.
|
|
35
38
|
* Robust without the bloat.
|
|
@@ -61,10 +64,14 @@ For Twig syntax:
|
|
|
61
64
|
|
|
62
65
|
npm install @rhinostone/swig-twig
|
|
63
66
|
|
|
67
|
+
For Python Jinja2 syntax:
|
|
68
|
+
|
|
69
|
+
npm install @rhinostone/swig-jinja2
|
|
70
|
+
|
|
64
71
|
Documentation
|
|
65
72
|
-------------
|
|
66
73
|
|
|
67
|
-
User-facing documentation lives in the Gina Docusaurus site under the [Swig Template Engine](https://gina.io/docs/swig) section, maintained in [gina-io/docs](https://github.com/gina-io/docs) at `docs/swig/`. The JSDoc blocks in `lib/swig.js`, `lib/filters.js`, `lib/tags/`, and `lib/loaders/` remain the canonical source-of-truth for the public API and are mirrored into the Docusaurus pages.
|
|
74
|
+
User-facing documentation lives in the Gina Docusaurus site under the [Swig Template Engine](https://gina.io/docs/swig) section, maintained in [gina-io/docs](https://github.com/gina-io/docs) at `docs/templating/swig/`. The JSDoc blocks in `lib/swig.js`, `lib/filters.js`, `lib/tags/`, and `lib/loaders/` remain the canonical source-of-truth for the public API and are mirrored into the Docusaurus pages.
|
|
68
75
|
|
|
69
76
|
Basic Example
|
|
70
77
|
-------------
|
|
@@ -109,7 +116,7 @@ Migrating from `@rhinostone/swig@1.x`
|
|
|
109
116
|
|
|
110
117
|
`@rhinostone/swig@2.x` is **drop-in for `1.x` consumers** — `swig.compileFile`, `swig.renderFile`, `swig.setFilter`, `swig.setTag`, and the rest of the public API are unchanged. The internal carve into [@rhinostone/swig-core](https://www.npmjs.com/package/@rhinostone/swig-core) is transparent (test gate during the alpha cycle: byte-identical compiled output against the `1.x` test suite).
|
|
111
118
|
|
|
112
|
-
`2.0.0` also ships [@rhinostone/swig-twig](https://www.npmjs.com/package/@rhinostone/swig-twig), a sibling Twig-syntax frontend. Switching is opt-in — your existing `@rhinostone/swig` install keeps working.
|
|
119
|
+
`2.0.0` also ships [@rhinostone/swig-twig](https://www.npmjs.com/package/@rhinostone/swig-twig), a sibling Twig-syntax frontend, and `2.5.0` adds [@rhinostone/swig-jinja2](https://www.npmjs.com/package/@rhinostone/swig-jinja2) for Python Jinja2 syntax. Switching is opt-in — your existing `@rhinostone/swig` install keeps working.
|
|
113
120
|
|
|
114
121
|
Migrating from Jinja2 or Django
|
|
115
122
|
-------------------------------
|
|
@@ -132,7 +139,7 @@ How it works
|
|
|
132
139
|
|
|
133
140
|
Swig reads template files and translates them into cached JavaScript functions. The pipeline is: parse → emit IR → lower IR to JS source → `new Function(...)`. At render time, the compiled function runs against a context object to produce the output string.
|
|
134
141
|
|
|
135
|
-
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)) 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.
|
|
142
|
+
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)) 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.
|
|
136
143
|
|
|
137
144
|
License
|
|
138
145
|
-------
|
package/ROADMAP.md
CHANGED
|
@@ -15,13 +15,25 @@ _No near-term scheduled items. See [Future (post-2.0)](#future-post-20) for upco
|
|
|
15
15
|
| Status | Item |
|
|
16
16
|
| --- | --- |
|
|
17
17
|
| Planned | Async parse path for dynamic targets — full support for `{% extends parent_var %}`, `{% include user_template %}`, and runtime-resolved `import` / `from` paths on the async-codegen branch. Static-target async dispatch shipped in 2.2.0; dynamic-target support is on hold pending consumer demand. |
|
|
18
|
-
| Planned | Ship
|
|
19
|
-
| Planned | Test framework migration. Replace mocha 1.x + expect.js with `node:test` + `node:assert/strict`,
|
|
18
|
+
| Planned | Ship a Django frontend as an additional `@rhinostone/swig-*` package. On demand — when there's concrete user demand. (The Jinja2 frontend shipped in `2.5.0`.) |
|
|
19
|
+
| Planned | Test framework migration. Replace mocha 1.x + expect.js with `node:test` + `node:assert/strict`, add a modern browser-test harness (the legacy phantomjs runner has been removed), swap blanket for `c8`. (The Node engines bump is upstream-driven by gina and is being treated as done.) |
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
## Completed
|
|
24
24
|
|
|
25
|
+
### v2.5.1 (May 2026)
|
|
26
|
+
|
|
27
|
+
- Restored JSDoc on the top-level `@rhinostone/swig` public API methods (`setFilter`, `setTag`, `setExtension`, `precompile`, `compile`, `compileFile`, `render`, `renderFile`, `run`, `invalidateCache`). The blocks were inadvertently stripped from `lib/swig.js` when the Swig constructor body was carved into `@rhinostone/swig-core` during the `2.0.0-alpha.1` cycle; `make build-docs` and IDE hover tooling read from `lib/swig.js`, so the documented surface for all ten methods had been missing since the carve. Doc-only restoration; `renderFile`'s block also documents the `v2.2.0` async-codegen dispatch (set `loader.async === true` on the loader to opt in).
|
|
28
|
+
- Cleaned two stale internal-process tracker references from `lib/tags/set.js` source comments; the explanatory content is preserved and only the dead reference tokens were dropped.
|
|
29
|
+
- Dev-tooling modernization riding the same release: retired the unmaintained `phantomjs` browser-test toolchain (also dropped the vulnerable `form-data` from the dev tree); bumped the example/development `express` dependency from `~3` to `^4` (also dropped the vulnerable `morgan` and `minimist` from the dev tree); bumped the test-utility `lodash` dependency from `~1.3.1` to `^4` (cleared five `lodash` advisories from the dev tree); migrated the test toolchain from `mocha` 1.12.0 to the Node built-in `node:test` runner with built-in line coverage (cleared the six remaining dev-tree audit findings, taking `npm audit` to zero); migrated the ESLint dev dependency from 8.x to 9.x with the new flat-config (`.eslintrc.json` → `eslint.config.js`), clearing the six "deprecated by maintainer" Socket Low alerts on the repo scan. None of this affects the published runtime — only the dev/CI toolchain.
|
|
30
|
+
- All four packages (`@rhinostone/swig`, `@rhinostone/swig-core`, `@rhinostone/swig-twig`, `@rhinostone/swig-jinja2`) released in lockstep at `2.5.1`. The runtime in `@rhinostone/swig-core` / `@rhinostone/swig-twig` / `@rhinostone/swig-jinja2` is functionally identical to `2.5.0`; only `@rhinostone/swig`'s `lib/swig.js` and `lib/tags/set.js` carry source-comment changes.
|
|
31
|
+
|
|
32
|
+
### v2.5.0 (May 2026)
|
|
33
|
+
|
|
34
|
+
- Added `@rhinostone/swig-jinja2`, a Python Jinja2-syntax frontend on the shared `@rhinostone/swig-core` engine — the third dialect in the multi-flavor family alongside native swig and `@rhinostone/swig-twig`. Ships 13 tags (`set`, `if` / `elif` / `else`, `for` with `else`, `block`, `extends`, `include`, `macro`, `import`, `from`, `raw`, `filter`, `with`, `autoescape`), 39 filters, and 16 `is` tests, plus the `**` / `//` / `~` operators, inline-if, Python slicing, and `{{- … -}}` whitespace control. Async loader support via `renderFileAsync` / `compileFileAsync`. Autoescape and the CVE-2023-25345 guards are inherited from `@rhinostone/swig-core`. Every filter and is-test was cross-checked against Python Jinja2 3.x; the behavioural differences (where the JavaScript runtime diverges from CPython) and the explicit non-goals (no sandboxed rendering, `{% call %}` / `{% do %}` / `{% trans %}`, the `map` / `select` filter family, macro kwargs) are documented in the Jinja2 templating guide.
|
|
35
|
+
- All four packages (`@rhinostone/swig`, `@rhinostone/swig-core`, `@rhinostone/swig-twig`, `@rhinostone/swig-jinja2`) released in lockstep at `2.5.0`. `@rhinostone/swig-core` gained additive `slice` and `coerceOutput` runtime helpers consumed by the Jinja2 frontend; native swig and Twig are functionally unchanged.
|
|
36
|
+
|
|
25
37
|
### v2.4.3 (May 2026)
|
|
26
38
|
|
|
27
39
|
- Fixed native `import` leaking an imported file's own import aliases into the importing template's scope. The `{% import %}` carry-through added in `2.4.1` emitted those nested imports bare into the caller's context, where the leaked alias could clobber a same-named caller variable, corrupt a macro when the caller later reassigned that name (macros read the live context at call time), or cascade across import depth. The nested imports are now re-homed under the importing alias and kept local to the file that declares them — matching `@rhinostone/swig-twig`'s scoping and the Jinja2/Twig import contract. Macros still resolve their own file's imports at call time.
|
package/dist/swig.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Swig v2.
|
|
1
|
+
/*! Swig v2.5.1 | https://github.com/gina-io/swig | @license https://github.com/gina-io/swig/blob/master/LICENSE */
|
|
2
2
|
/*! DateZ (c) 2011 Tomo Universalis | @license https://github.com/ocrybit/DateZ/blob/master/LISENCE */
|
|
3
3
|
(() => {
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -139,6 +139,68 @@
|
|
|
139
139
|
}
|
|
140
140
|
return out;
|
|
141
141
|
};
|
|
142
|
+
exports.slice = function(obj, start, stop, step) {
|
|
143
|
+
var isString = typeof obj === "string", length, lower, upper, s, e, result = [], i;
|
|
144
|
+
function toInt(n) {
|
|
145
|
+
n = Number(n);
|
|
146
|
+
if (isNaN(n)) {
|
|
147
|
+
return NaN;
|
|
148
|
+
}
|
|
149
|
+
return n < 0 ? Math.ceil(n) : Math.floor(n);
|
|
150
|
+
}
|
|
151
|
+
function clamp(v, dflt) {
|
|
152
|
+
if (v === null || v === void 0) {
|
|
153
|
+
return dflt;
|
|
154
|
+
}
|
|
155
|
+
v = toInt(v);
|
|
156
|
+
if (isNaN(v)) {
|
|
157
|
+
return dflt;
|
|
158
|
+
}
|
|
159
|
+
if (v < 0) {
|
|
160
|
+
v += length;
|
|
161
|
+
if (v < lower) {
|
|
162
|
+
v = lower;
|
|
163
|
+
}
|
|
164
|
+
} else if (v > upper) {
|
|
165
|
+
v = upper;
|
|
166
|
+
}
|
|
167
|
+
return v;
|
|
168
|
+
}
|
|
169
|
+
if (obj === null || obj === void 0 || typeof obj.length !== "number") {
|
|
170
|
+
return isString ? "" : [];
|
|
171
|
+
}
|
|
172
|
+
length = obj.length;
|
|
173
|
+
if (step === null || step === void 0) {
|
|
174
|
+
step = 1;
|
|
175
|
+
} else {
|
|
176
|
+
step = toInt(step);
|
|
177
|
+
if (isNaN(step) || step === 0) {
|
|
178
|
+
step = 1;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (step < 0) {
|
|
182
|
+
lower = -1;
|
|
183
|
+
upper = length - 1;
|
|
184
|
+
} else {
|
|
185
|
+
lower = 0;
|
|
186
|
+
upper = length;
|
|
187
|
+
}
|
|
188
|
+
s = clamp(start, step < 0 ? upper : lower);
|
|
189
|
+
e = clamp(stop, step < 0 ? lower : upper);
|
|
190
|
+
if (step > 0) {
|
|
191
|
+
for (i = s; i < e; i += step) {
|
|
192
|
+
result.push(obj[i]);
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
for (i = s; i > e; i += step) {
|
|
196
|
+
result.push(obj[i]);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return isString ? result.join("") : result;
|
|
200
|
+
};
|
|
201
|
+
exports.coerceOutput = function(v) {
|
|
202
|
+
return v === null || v === void 0 ? "" : v;
|
|
203
|
+
};
|
|
142
204
|
}
|
|
143
205
|
});
|
|
144
206
|
|
|
@@ -1366,7 +1428,22 @@
|
|
|
1366
1428
|
return;
|
|
1367
1429
|
}
|
|
1368
1430
|
});
|
|
1369
|
-
|
|
1431
|
+
var forEmptyCheck = " if (!__l) { return; }\n";
|
|
1432
|
+
if (node.emptyBody) {
|
|
1433
|
+
var forEmptyJS = "";
|
|
1434
|
+
utils.each(node.emptyBody, function(b) {
|
|
1435
|
+
if (b.type === "LegacyJS") {
|
|
1436
|
+
forEmptyJS += b.js;
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
if (b.type === "Text" || b.type === "Raw") {
|
|
1440
|
+
forEmptyJS += '_output += "' + escapeTextValue(b.value) + '";\n';
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
});
|
|
1444
|
+
forEmptyCheck = " if (!__l || !__len) {\n" + forEmptyJS + " return;\n }\n";
|
|
1445
|
+
}
|
|
1446
|
+
out += "(function () {\n var __l = " + forIterable + ', __len = (_utils.isArray(__l) || typeof __l === "string") ? __l.length : _utils.keys(__l).length;\n' + forEmptyCheck + " var " + ctxloopcache + " = { loop: " + ctxloop + ", " + forVal + ": " + ctx + forVal + ", " + forKey + ": " + ctx + forKey + " };\n " + ctxloop + " = { first: false, index: 1, index0: 0, revindex: __len, revindex0: __len - 1, length: __len, last: false };\n _utils.each(__l, function (" + forVal + ", " + forKey + ") {\n " + ctx + forVal + " = " + forVal + ";\n " + ctx + forKey + " = " + forKey + ";\n " + ctxloop + ".key = " + forKey + ";\n " + ctxloop + ".first = (" + ctxloop + ".index0 === 0);\n " + ctxloop + ".last = (" + ctxloop + ".revindex0 === 0);\n " + forBodyJS + " " + ctxloop + ".index += 1; " + ctxloop + ".index0 += 1; " + ctxloop + ".revindex -= 1; " + ctxloop + ".revindex0 -= 1;\n });\n " + ctxloop + " = " + ctxloopcache + ".loop;\n " + ctx + forVal + " = " + ctxloopcache + "." + forVal + ";\n " + ctx + forKey + " = " + ctxloopcache + "." + forKey + ";\n " + ctxloopcache + " = undefined;\n})();\n";
|
|
1370
1447
|
return;
|
|
1371
1448
|
}
|
|
1372
1449
|
if (node.type === "Macro") {
|
|
@@ -1381,11 +1458,14 @@
|
|
|
1381
1458
|
return;
|
|
1382
1459
|
}
|
|
1383
1460
|
});
|
|
1384
|
-
var macroParams = node.params || [], macroSigJS, macroIndexOfJS;
|
|
1461
|
+
var macroParams = node.params || [], macroSigJS, macroIndexOfJS, macroDefaultsJS = "";
|
|
1385
1462
|
if (macroParams.length && typeof macroParams[0] === "object" && macroParams[0] !== null && typeof macroParams[0].name === "string") {
|
|
1386
1463
|
var macroNames = [];
|
|
1387
1464
|
utils.each(macroParams, function(p) {
|
|
1388
1465
|
macroNames.push(p.name);
|
|
1466
|
+
if (p["default"]) {
|
|
1467
|
+
macroDefaultsJS += " if (" + p.name + " === undefined) { " + p.name + " = " + exports.emitExpr(p["default"]) + "; }\n";
|
|
1468
|
+
}
|
|
1389
1469
|
});
|
|
1390
1470
|
macroSigJS = macroNames.join(", ");
|
|
1391
1471
|
var macroJsonNames = [];
|
|
@@ -1397,7 +1477,7 @@
|
|
|
1397
1477
|
macroSigJS = macroParams.join("");
|
|
1398
1478
|
macroIndexOfJS = '"' + macroParams.join('","') + '"';
|
|
1399
1479
|
}
|
|
1400
|
-
out += "_ctx." + node.name + " = function (" + macroSigJS + ') {\n var _output = "",\n __ctx = _utils.extend({}, _ctx);\n _utils.each(_ctx, function (v, k) {\n if ([
|
|
1480
|
+
out += "_ctx." + node.name + " = function (" + macroSigJS + ') {\n var _output = "",\n __ctx = _utils.extend({}, _ctx);\n' + macroDefaultsJS + " _utils.each(_ctx, function (v, k) {\n if ([" + macroIndexOfJS + "].indexOf(k) !== -1) { delete _ctx[k]; }\n });\n" + macroBodyJS + "\n _ctx = _utils.extend(_ctx, __ctx);\n return _output;\n};\n_ctx." + node.name + ".safe = true;\n";
|
|
1401
1481
|
if (options && options.codegenMode === "async") {
|
|
1402
1482
|
if (_security.dangerousProps.indexOf(node.name) !== -1) {
|
|
1403
1483
|
throw new Error('Macro name "' + node.name + '" is reserved.');
|
|
@@ -1625,7 +1705,11 @@
|
|
|
1625
1705
|
outExprJS = '_filters["' + fc.name + '"](' + outExprJS + fcArgsJS + ")";
|
|
1626
1706
|
});
|
|
1627
1707
|
}
|
|
1628
|
-
|
|
1708
|
+
if (node.coerce) {
|
|
1709
|
+
out += "_output += _utils.coerceOutput(" + outExprJS + ");\n";
|
|
1710
|
+
} else {
|
|
1711
|
+
out += "_output += " + outExprJS + ";\n";
|
|
1712
|
+
}
|
|
1629
1713
|
return;
|
|
1630
1714
|
}
|
|
1631
1715
|
if (node.type === "Filter") {
|
|
@@ -2356,9 +2440,9 @@
|
|
|
2356
2440
|
* `parseExpr` emits structured IR that {@link backend.emitExpr}
|
|
2357
2441
|
* later lowers into an equivalent JS-source fragment. `.parse()` is
|
|
2358
2442
|
* unchanged and remains the production path; `parseExpr` is the
|
|
2359
|
-
* incoming target shape for
|
|
2360
|
-
*
|
|
2361
|
-
*
|
|
2443
|
+
* incoming target shape for the IR migration, introduced additively
|
|
2444
|
+
* so the IR grammar can be proven against real lexer output before
|
|
2445
|
+
* consumers are flipped over to it.
|
|
2362
2446
|
*
|
|
2363
2447
|
* The CVE-2023-25345 prototype-chain guards (`_dangerousProps` on
|
|
2364
2448
|
* VAR segments, DOTKEY matches, STRING-inside-BRACKETOPEN values,
|
|
@@ -4598,7 +4682,7 @@
|
|
|
4598
4682
|
var loaders = require_loaders2();
|
|
4599
4683
|
var preWalker = require_pre_walker();
|
|
4600
4684
|
var engine = require_engine();
|
|
4601
|
-
exports.version = "2.
|
|
4685
|
+
exports.version = "2.5.1";
|
|
4602
4686
|
var defaultOptions = {
|
|
4603
4687
|
autoescape: true,
|
|
4604
4688
|
varControls: ["{{", "}}"],
|