@rhinostone/swig 2.0.0-alpha.8 → 2.0.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.
Files changed (35) hide show
  1. package/.changes/v1.0.0-pre1.md +2 -2
  2. package/.changes/v1.0.0.md +1 -1
  3. package/.changes/v2.0.0.md +6 -0
  4. package/.changes/v2.0.1.md +8 -0
  5. package/.playwright-mcp/console-2026-04-22T15-34-20-480Z.log +2 -0
  6. package/.playwright-mcp/console-2026-04-22T15-35-04-265Z.log +11 -0
  7. package/.playwright-mcp/console-2026-04-22T15-37-26-953Z.log +1 -0
  8. package/.playwright-mcp/console-2026-04-22T15-51-15-160Z.log +148 -0
  9. package/.playwright-mcp/console-2026-04-22T15-51-33-405Z.log +74 -0
  10. package/.playwright-mcp/console-2026-04-22T15-51-53-922Z.log +74 -0
  11. package/.playwright-mcp/console-2026-04-22T15-53-10-736Z.log +74 -0
  12. package/.playwright-mcp/console-2026-04-22T15-53-40-091Z.log +883 -0
  13. package/.playwright-mcp/console-2026-04-22T16-12-02-541Z.log +74 -0
  14. package/.playwright-mcp/console-2026-04-22T16-33-44-982Z.log +13973 -0
  15. package/.playwright-mcp/page-2026-04-22T15-34-24-524Z.yml +1 -0
  16. package/.playwright-mcp/page-2026-04-22T15-35-04-346Z.yml +0 -0
  17. package/.playwright-mcp/page-2026-04-22T15-37-27-039Z.yml +5 -0
  18. package/.playwright-mcp/page-2026-04-22T15-51-15-600Z.yml +76 -0
  19. package/.playwright-mcp/page-2026-04-22T15-51-33-605Z.yml +0 -0
  20. package/.playwright-mcp/page-2026-04-22T15-51-54-206Z.yml +676 -0
  21. package/.playwright-mcp/page-2026-04-22T15-53-11-277Z.yml +632 -0
  22. package/.playwright-mcp/page-2026-04-22T15-53-40-297Z.yml +0 -0
  23. package/.playwright-mcp/page-2026-04-22T16-12-02-855Z.yml +0 -0
  24. package/.playwright-mcp/page-2026-04-22T16-33-45-281Z.yml +0 -0
  25. package/AUTHORS +1 -1
  26. package/HISTORY.md +19 -3
  27. package/README.md +33 -7
  28. package/ROADMAP.md +36 -8
  29. package/dist/swig.js +5 -5
  30. package/dist/swig.min.js +3 -3
  31. package/dist/swig.min.js.map +1 -1
  32. package/lib/lexer.js +1 -1
  33. package/lib/parser.js +2 -2
  34. package/lib/swig.js +2 -2
  35. package/package.json +2 -2
package/HISTORY.md CHANGED
@@ -1,3 +1,19 @@
1
+ [2.0.1](https://github.com/gina-io/swig/tree/v2.0.1) / 2026-05-10
2
+ -----------------------------------------------------------------
3
+
4
+ * **Fixed** Fixed bracket-access expressions failing on unspaced binary arithmetic in both `@rhinostone/swig` and `@rhinostone/swig-twig`. The lexer NUMBER rule's optional sign prefix (`[+\-]?`) greedy-ate a leading operator inside bracket expressions — `arr[arr.length-1]` and `arr[idx-1]` lexed as VAR + DOTKEY/VAR + NUMBER(-1) + `]`, and parsePostfix then bailed with "Unexpected closing square bracket". Dropped the optional sign from both `lib/lexer.js` and `packages/swig-twig/lib/lexer.js`; parsePrimary's OPERATOR branch already wraps unary `-` / `+` as IRUnaryOp via parseUnary, so signed-literal paths (`{% set x = -5 %}`, `{{ a + -5 }}`) continue to work and the backend's emitUnaryOp produces byte-identical JS for negative numbers (the `emit('-1.5') === '-1.5'` round-trip is unchanged). Three pre-existing parse/lexer assertions documented the old "NUMBER rule, not UnaryOp" choice and were rewritten to assert the new IRUnaryOp shape; a regression suite covers `arr[arr.length-1]` / `arr[idx-1]` / `arr[idx+0]` / `arr[idx-2]` plus a `*` / `/` round-trip sweep on both render surfaces.
5
+
6
+ * **Fixed** Fixed missing whitespace-control parity in `@rhinostone/swig-twig`. `{{- … -}}` and `{%- … -%}` markers now strip surrounding whitespace at chunk boundaries, matching the native swig surface and the upstream Twig spec. Previously absent — `packages/swig-twig/lib/parser.js` had only a basic strip regex and no `varStripBefore` / `*After` / `tagStripBefore` / `*After` detection regexes, so `{{- foo -}}` either rendered as junk or threw "Unexpected end of expression". Implementation mirrors the native chunk-boundary pattern (`stripPrev` / `stripNext` flags, `stripPrevToken` helper) with the corrected strip-regex shape baked in from day one (`-?` adjacent to the open / close marker only, not after `\s*`), so negative-literal expressions like `{{ -5 }}` and `{{- -5 -}}` compose correctly. New `tests/swig-twig/whitespace.test.js` covers the six mirror-of-native cases (strips before / after / both, on `{{...}}` and `{%...%}`) plus four negative-literal composition cases. Same one-level-deep limitation as native — a `{%- endif %}` strips the trailing whitespace of the immediately enclosing tag's last child only, not deeper.
7
+
8
+ * **Fixed** Fixed `varStrip` / `tagStrip` regexes in `lib/parser.js` greedy-eating the leading `-` of negative-number expressions. The strip patterns were `^{{-?\s*-?|-?\s*-?}}$` (and the tag-form equivalent) — the second `-?` after `\s*` matched the leading `-` of an expression as if it were a whitespace-control marker, so `{{ -5 }}` and `{{ -1.5 }}` rendered as `"5"` / `"1.5"` (the sign was eaten before the lexer ever saw the chunk). Dropped the inner `-?` from both regexes; whitespace-control now fires only when `-` is immediately adjacent to the open / close marker (`{{-`, `-}}`, `{%-`, `-%}`), matching the standard Twig/Jinja2 contract. Existing whitespace strip-control tests continue to pass, and a new regression case covers negative literals plain, with strip-control before / after / both, plus a check that strip-control on regular variables still composes correctly. `@rhinostone/swig-twig` was unaffected — its parser-side strip regex (`packages/swig-twig/lib/parser.js`) is a simpler `^{{ \s*|\s* }}$` with no `-?` markers, so the same shape doesn't apply (a side-effect of the verification surfaced that swig-twig has no whitespace-control support today; tracked separately).
9
+
10
+ [2.0.0](https://github.com/gina-io/swig/tree/v2.0.0) / 2026-05-06
11
+ -----------------------------------------------------------------
12
+
13
+ * **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 `http://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.
14
+
15
+ * **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.
16
+
1
17
  [2.0.0-alpha.8](https://github.com/gina-io/swig/tree/v2.0.0-alpha.8) / 2026-04-20
2
18
  ---------------------------------------------------------------------------------
3
19
 
@@ -186,7 +202,7 @@
186
202
  * **Fixed** Allow parent and other tags to work correctly nested in other tags. gh-331
187
203
  * **Fixed** Prevent lexer from matching partial logic/words in variables. gh-330
188
204
 
189
- Migrating from v0.x.x? View the [Migration Guide](https://github.com/paularmstrong/swig/wiki/Migrating-from-v0.x.x-to-v1.0.0)
205
+ Migrating from v0.x.x? The upstream wiki has since been deleted; see the individual breaking-change entries below.
190
206
 
191
207
  [1.0.0-rc3](https://github.com/paularmstrong/swig/tree/v1.0.0-rc3) / 2013-09-14
192
208
  -------------------------------------------------------------------------------
@@ -259,8 +275,8 @@ Migrating from v0.x.x? View the [Migration Guide](https://github.com/paularmstro
259
275
  * **Changed** Template parsing has been completely rewritten
260
276
  * **Changed** `swig.compileFile` returns a function that renders templates, not an object
261
277
  * **Changed** Express-compatible using `swig.renderFile`.
262
- * **Changed** `extends`, `import`, and `include` now reference files with relative paths from the current file ([info](https://github.com/paularmstrong/swig/wiki/Migrating-from-v0.x.x-to-v1.0.0#extends-include-import-changes)).
263
- * **Changed** `extends` may no longer accept variables ([info](https://github.com/paularmstrong/swig/wiki/Migrating-from-v0.x.x-to-v1.0.0#extends-include-import-changes)).
278
+ * **Changed** `extends`, `import`, and `include` now reference files with relative paths from the current file.
279
+ * **Changed** `extends` may no longer accept variables.
264
280
  * **Changed** `else if` tag is now `elseif` or `elif`.
265
281
  * **Changed** Removed `only` argument from `include`.
266
282
  * **Changed** allow `_`, `$` to start var names in templates.
package/README.md CHANGED
@@ -1,37 +1,54 @@
1
1
  Swig
2
2
  ====
3
3
 
4
- [![CI](https://github.com/gina-io/swig/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/gina-io/swig/actions/workflows/ci.yml) [![NPM version](http://img.shields.io/npm/v/@rhinostone/swig.svg?style=flat)](https://www.npmjs.org/package/@rhinostone/swig) [![NPM Downloads](http://img.shields.io/npm/dm/@rhinostone/swig.svg?style=flat)](https://www.npmjs.org/package/@rhinostone/swig) [![Socket Badge](https://socket.dev/api/badge/npm/package/@rhinostone/swig)](https://socket.dev/npm/package/@rhinostone/swig)
4
+ [![CI](https://github.com/gina-io/swig/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/gina-io/swig/actions/workflows/ci.yml) [![NPM version](http://img.shields.io/npm/v/@rhinostone/swig.svg?style=flat)](https://www.npmjs.com/package/@rhinostone/swig) [![NPM Downloads](http://img.shields.io/npm/dm/@rhinostone/swig.svg?style=flat)](https://www.npmjs.com/package/@rhinostone/swig) [![Socket Badge](https://socket.dev/api/badge/npm/package/@rhinostone/swig)](https://socket.dev/npm/package/@rhinostone/swig)
5
5
 
6
- > **Maintained fork.** This is [gina-io/swig](https://github.com/gina-io/swig), a maintained fork of the abandoned [paularmstrong/swig](https://github.com/paularmstrong/swig). Security fixes and critical bug fixes land here; no new features are planned. The original project has not had a release since 2014.
6
+ > **Multi-flavor template engine** for Node.js and browsers — native Swig syntax (Jinja2/Django-inspired) and Twig 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
- > **Part of the [Gina](https://github.com/gina-io/gina) ecosystem.** This fork 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.
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
 
10
10
  Swig is a **Jinja2/Django-inspired** template engine for node.js and browsers. The syntax will feel familiar to Jinja2 and Django users, but Swig is **not drop-in compatible** with either — porting templates from an existing project requires a handful of changes. See the [Migration Guide](https://gina.io/docs/swig/migration) for the full parity list and workaround patterns.
11
11
 
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
+
14
+ Workspace packages
15
+ ------------------
16
+
17
+ | Package | Description | When to use |
18
+ | --- | --- | --- |
19
+ | [`@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
+ | [`@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. |
21
+ | [`@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
+
23
+ Each frontend pins the matching `@rhinostone/swig-core` version exactly during the alpha cycle — the IR is not stable across alpha minors. From `2.0.0` stable onward, frontends and the core release in lockstep.
24
+
12
25
  Features
13
26
  --------
14
27
 
15
- * Available for node.js **and** major web browsers!
28
+ * Available for node.js **and** major web browsers.
16
29
  * [Express](http://expressjs.com/) compatible.
17
30
  * Object-Oriented template inheritance.
18
31
  * Apply filters and transformations to output in your templates.
19
32
  * Automatically escapes all output for safe HTML rendering.
20
33
  * Lots of iteration and conditionals supported.
21
34
  * Robust without the bloat.
22
- * Extendable and customizable. See [Swig-Extras](https://github.com/paularmstrong/swig-extras) (abandoned, kept for reference) for some examples.
35
+ * Extendable and customizable register custom filters, tags, and loaders per-instance.
23
36
 
24
37
  Need Help? Have Questions? Comments?
25
38
  ------------------------------------
26
39
 
27
40
  * File an issue at [gina-io/swig/issues](https://github.com/gina-io/swig/issues).
28
- * [Swig v0.x → v1.x migration notes](https://github.com/paularmstrong/swig/wiki/Migrating-from-v0.x.x-to-v1.0.0) — original upstream wiki, still authoritative for that version jump. (For porting *from Jinja2 or Django* into Swig, see the [Migration Guide](https://gina.io/docs/swig/migration) below.)
41
+ * Swig v0.x → v1.x migration notes — the original upstream wiki has been deleted; see `HISTORY.md` entries around v1.0.0 for the individual breaking changes. For porting *from Jinja2 or Django* into Swig, see the [Migration Guide](https://gina.io/docs/swig/migration).
29
42
 
30
43
  Installation
31
44
  ------------
32
45
 
33
46
  npm install @rhinostone/swig
34
47
 
48
+ For Twig syntax:
49
+
50
+ npm install @rhinostone/swig-twig
51
+
35
52
  Documentation
36
53
  -------------
37
54
 
@@ -75,6 +92,13 @@ var output = template({
75
92
 
76
93
  For working example see [examples/basic](https://github.com/gina-io/swig/tree/master/examples/basic).
77
94
 
95
+ Migrating from `@rhinostone/swig@1.x`
96
+ -------------------------------------
97
+
98
+ `@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).
99
+
100
+ `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.
101
+
78
102
  Migrating from Jinja2 or Django
79
103
  -------------------------------
80
104
 
@@ -94,7 +118,9 @@ Full parity tables and workaround patterns: **[Migration Guide](https://gina.io/
94
118
  How it works
95
119
  ------------
96
120
 
97
- Swig reads template files and translates them into cached javascript functions. When we later render a template we call the evaluated function, passing a context object as an argument.
121
+ 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.
122
+
123
+ 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.
98
124
 
99
125
  License
100
126
  -------
package/ROADMAP.md CHANGED
@@ -8,24 +8,52 @@ For bug reports and feature requests, file an issue at [gina-io/swig](https://gi
8
8
 
9
9
  ## Next
10
10
 
11
- | Status | Item |
12
- | --- | --- |
13
- | Planned | Port the native Swig frontend to emit IR instead of JS directly. Test gate: byte-identical compiled output for existing suites. Target: `2.0.0-alpha.2`. |
11
+ _No near-term scheduled items. See [Future (post-2.0)](#future-post-20) for upcoming work._
14
12
 
15
13
  ## Future (post-2.0)
16
14
 
17
- Multi-flavor architecture — a single backend with swappable frontends so Twig / Jinja2 / Django templates can run on the same compile pipeline. Design: `multi-flavor-ir.md`.
18
-
19
15
  | Status | Item |
20
16
  | --- | --- |
21
- | Planned | Ship `@rhinostone/swig-twig` frontend expression sugar (`~`, `??`, `?:`, `..`, `is X`, `not in`, `#{}`), Twig tag rewrites (`apply`, `verbatim`, `set/endset`, `with/endwith`, `from import`), ~20 filter parity. |
22
- | Planned | Ship Jinja2 and Django frontends. On demand when there's concrete user demand. |
23
- | Planned | Engine bump + test framework migration. Move to Node ≥ 18, `node:test` + `node:assert/strict`, swap mocha-phantomjs for a modern browser-test harness, swap blanket for `c8`. Bundled with `2.0.0`. |
17
+ | Planned | Ship Jinja2 and Django frontends as additional `@rhinostone/swig-*` packages. On demand when there's concrete user demand. |
18
+ | Planned | Test framework migration. Replace mocha 1.x + expect.js with `node:test` + `node:assert/strict`, swap mocha-phantomjs for a modern browser-test harness, swap blanket for `c8`. (The Node engines bump is upstream-driven by gina and is being treated as done.) |
24
19
 
25
20
  ---
26
21
 
27
22
  ## Completed
28
23
 
24
+ ### v2.0.1 (May 2026)
25
+
26
+ - Fixed bracket-access expressions failing on unspaced binary arithmetic in `@rhinostone/swig` and `@rhinostone/swig-twig`. The lexer's NUMBER rule was greedy-eating leading `+` / `-` operators inside bracket expressions like `arr[arr.length-1]` and `arr[idx-1]`, causing the parser to bail with "Unexpected closing square bracket". Dropped the optional sign prefix from the NUMBER rule; signed-literal paths continue to work via the existing unary-operator wrapping.
27
+ - Fixed `varStrip` / `tagStrip` regexes in `lib/parser.js` greedy-eating the leading `-` of negative-number expressions. `{{ -5 }}` and `{{ -1.5 }}` were rendering as `"5"` / `"1.5"` because the strip patterns matched the sign before the lexer saw it. Whitespace-control markers (`{{-`, `-}}`, `{%-`, `-%}`) now fire only when `-` is immediately adjacent to the open / close marker, matching the standard Twig/Jinja2 contract.
28
+ - Fixed missing whitespace-control parity in `@rhinostone/swig-twig`. `{{- … -}}` and `{%- … -%}` markers now strip surrounding whitespace at chunk boundaries, matching the native swig surface and the upstream Twig spec. Same one-level-deep limitation as native — a `{%- endif %}` strips the trailing whitespace of the immediately enclosing tag's last child only, not deeper.
29
+
30
+ ### v2.0.0 (May 2026)
31
+
32
+ - Multi-flavor template-engine workspace shipped: `@rhinostone/swig` (native syntax, drop-in for `1.x`), `@rhinostone/swig-twig` (Twig syntax), `@rhinostone/swig-core` (shared IR backend). Production-ready cut of the changeset introduced across `2.0.0-alpha.1` through `2.0.0-alpha.5`. No functional or API changes since `2.0.0-alpha.5`. IR ABI is stable from this release onward; cross-package dependencies pin exact versions and frontends + core release in lockstep.
33
+ - README messaging refreshed across all three packages to reflect production-ready status; package descriptions cleaned of historical internal-tracking references; stale documentation URLs refreshed.
34
+ - Repository unforked from `paularmstrong/swig` on GitHub once the multi-flavor track stabilised — gina-io/swig is now a standalone project rather than a fork. Attribution preserved via `LICENSE` and `package.json.author`.
35
+
36
+ ### v2.0.0-alpha.8 (April 2026)
37
+
38
+ - Remove the soft-deprecated `exports.parse(source, options)` wrapper (Path B) from `@rhinostone/swig-twig`. Soft-deprecated since `2.0.0-alpha.4`; removed now so any remaining consumer surfaces during the alpha.8 bake window before `2.0.0` stable. Migrate to the per-instance API installed by `engine.install`: `new twig.Twig(opts)` (or the default instance `exports.precompile` / `exports.compile` / `exports.render` / `exports.renderFile`). Internal plumbing (`exports.parser.parse`, `exports.parseFile`) is unaffected.
39
+
40
+ ### v2.0.0-alpha.5 (April 2026)
41
+
42
+ - Twig render-path polish — fix `~` string-concat SyntaxError in the shared backend; route literal LHS (STRING/NUMBER/BOOL) through `parsePostfix` so `{{ "hi"|upper }}` works; land a 19-fixture render corpus under `tests/swig-twig/cases/`.
43
+ - Scope-closing Twig expression sugar: `..` range via `_utils.range`; `??` undefined-fallback via new `IRVarRefExists` IR node; `is <test>` routed through `_ext._test_<name>` with seven built-in tests (`defined`, `null`, `empty`, `iterable`, `odd`, `even`, `divisibleby`).
44
+
45
+ ### v2.0.0-alpha.4 (April 2026)
46
+
47
+ - Wire `@rhinostone/swig-twig` for Path A render via `engine.install(self, frontend)`; isolate per-instance tags and filters; soft-deprecate the Path B `exports.parse` wrapper with a one-shot `console.warn`.
48
+
49
+ ### v2.0.0-alpha.3 (April 2026)
50
+
51
+ - Ship `@rhinostone/swig-twig` parser surface — Twig lexer, Pratt parser, 8 built-in tags (`apply`, `verbatim`, `set/endset`, `with/endwith`, `from import`, plus native parity), 5 Twig-specific tags, 24 filter parity. Lockstep cut of `swig-core` + `swig` + `swig-twig` fixes the broken `alpha.2` missing-dep regression.
52
+
53
+ ### v2.0.0-alpha.2 (April 2026)
54
+
55
+ - Port the native Swig frontend to emit IR instead of JS directly. All built-in tags and TokenParser expression codegen now route through `@rhinostone/swig-core`'s IR → backend pipeline. Test gate: byte-identical compiled output for existing suites.
56
+
29
57
  ### v2.0.0-alpha.1 (April 2026)
30
58
 
31
59
  - Carve `@rhinostone/swig-core` — extract IR stubs, backend (JS codegen), runtime (cache, loader, filter infra, `_dangerousProps` guards), lexer token-type enum, and TokenParser into a standalone workspace package. `@rhinostone/swig` becomes the native-syntax frontend plus a core re-export. Phase 1 of the multi-flavor architecture.
package/dist/swig.js CHANGED
@@ -1,5 +1,5 @@
1
- /*! Swig v2.0.0-alpha.8 | 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/TomoUniversalis/DateZ/blob/master/LISENCE */
1
+ /*! Swig v2.0.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/ocrybit/DateZ/blob/master/LISENCE */
3
3
  (() => {
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __commonJS = (cb, mod) => function __require() {
@@ -1828,7 +1828,7 @@
1828
1828
  {
1829
1829
  type: TYPES.NUMBER,
1830
1830
  regex: [
1831
- /^[+\-]?\d+(\.\d+)?/
1831
+ /^\d+(\.\d+)?/
1832
1832
  ]
1833
1833
  },
1834
1834
  {
@@ -2689,7 +2689,7 @@
2689
2689
  }
2690
2690
  exports.parse = function(swig2, source, opts, tags, filters) {
2691
2691
  source = source.replace(/\r\n/g, "\n");
2692
- var escape = opts.autoescape, tagOpen = opts.tagControls[0], tagClose = opts.tagControls[1], varOpen = opts.varControls[0], varClose = opts.varControls[1], escapedTagOpen = escapeRegExp(tagOpen), escapedTagClose = escapeRegExp(tagClose), escapedVarOpen = escapeRegExp(varOpen), escapedVarClose = escapeRegExp(varClose), tagStrip = new RegExp("^" + escapedTagOpen + "-?\\s*-?|-?\\s*-?" + escapedTagClose + "$", "g"), tagStripBefore = new RegExp("^" + escapedTagOpen + "-"), tagStripAfter = new RegExp("-" + escapedTagClose + "$"), varStrip = new RegExp("^" + escapedVarOpen + "-?\\s*-?|-?\\s*-?" + escapedVarClose + "$", "g"), varStripBefore = new RegExp("^" + escapedVarOpen + "-"), varStripAfter = new RegExp("-" + escapedVarClose + "$"), cmtOpen = opts.cmtControls[0], cmtClose = opts.cmtControls[1], anyChar = "[\\s\\S]*?", splitter = new RegExp(
2692
+ var escape = opts.autoescape, tagOpen = opts.tagControls[0], tagClose = opts.tagControls[1], varOpen = opts.varControls[0], varClose = opts.varControls[1], escapedTagOpen = escapeRegExp(tagOpen), escapedTagClose = escapeRegExp(tagClose), escapedVarOpen = escapeRegExp(varOpen), escapedVarClose = escapeRegExp(varClose), tagStrip = new RegExp("^" + escapedTagOpen + "-?\\s*|\\s*-?" + escapedTagClose + "$", "g"), tagStripBefore = new RegExp("^" + escapedTagOpen + "-"), tagStripAfter = new RegExp("-" + escapedTagClose + "$"), varStrip = new RegExp("^" + escapedVarOpen + "-?\\s*|\\s*-?" + escapedVarClose + "$", "g"), varStripBefore = new RegExp("^" + escapedVarOpen + "-"), varStripAfter = new RegExp("-" + escapedVarClose + "$"), cmtOpen = opts.cmtControls[0], cmtClose = opts.cmtControls[1], anyChar = "[\\s\\S]*?", splitter = new RegExp(
2693
2693
  "(" + escapedTagOpen + anyChar + escapedTagClose + "|" + escapedVarOpen + anyChar + escapedVarClose + "|" + escapeRegExp(cmtOpen) + anyChar + escapeRegExp(cmtClose) + ")"
2694
2694
  ), line = 1, stack = [], parent = null, tokens = [], blocks = {}, inRaw = false, stripNext;
2695
2695
  function parseVariable(str, line2) {
@@ -4079,7 +4079,7 @@
4079
4079
  var dateformatter = require_dateformatter2();
4080
4080
  var loaders = require_loaders2();
4081
4081
  var engine = require_engine();
4082
- exports.version = "2.0.0-alpha.8";
4082
+ exports.version = "2.0.1";
4083
4083
  var defaultOptions = {
4084
4084
  autoescape: true,
4085
4085
  varControls: ["{{", "}}"],